When you deploy the service behind a forwarder, in-flight webhooks hit a target that is restarting. They fail, retry, and may land in the DLQ. Pausing the forwarder first turns that failure window into a queue window: inbound events are held, the deploy proceeds, and a resume drains the backlog into the healthy target. The agent's job is to bracket the deploy and then prove recovery.
forwarder pause and forwarder resume drop into an interactive picker when run without selectors. An agent must always pass both --bucket (-b) and --forwarder (-f) so the command runs non-interactively. Omitting either fails fast with "both --bucket (-b) and --forwarder (-f) flags are required".
The deploy window#
sequenceDiagram
participant A as Agent
participant R as Repost
participant T as Target service
A->>R: forwarder pause -f prod-api
Note over R,T: inbound webhooks queue, not dropped
A->>T: deploy new version
A->>R: forwarder resume -f prod-api
R->>T: drain queued deliveries
A->>R: expect / health --fail-on
R-->>A: recovery confirmedPause before deploying#
Pausing is a write mutation. Webhooks received while the forwarder is paused are queued, not discarded, and deliver when you resume.
repost forwarder pause \
--bucket stripe-prod \
--forwarder prod-api \
--json{
"schema": "repost.forwarder.action/v1",
"data": {
"outcome": "PAUSED",
"results": [
{ "name": "prod-api", "target": "https://api.example.com/webhooks", "type": "EXTERNAL", "success": true }
]
}
}Confirm every entry in results has success: true before deploying. --forwarder is repeatable. Pass it once per forwarder that points at the service you are deploying, and verify each one paused.
Deploy, then resume#
Run your deployment out of band. When the target is healthy again, resume. Queued deliveries begin draining immediately.
repost forwarder resume \
--bucket stripe-prod \
--forwarder prod-api \
--json{
"schema": "repost.forwarder.action/v1",
"data": {
"outcome": "RESUMED",
"results": [
{ "name": "prod-api", "target": "https://api.example.com/webhooks", "type": "EXTERNAL", "success": true }
]
}
}Resuming releases the entire queued backlog at once. If the target is sensitive to bursts, cap delivery with the forwarder's --rate-limit-per-second (set at creation) before the deploy, not after the flood starts.
Confirm recovery#
Do not call a deploy healthy because resume returned success: true. That only confirms the forwarder is unpaused. Confirm a real delivery succeeded.
repost expect \
--bucket stripe-prod \
--filter 'method:POST AND path:/stripe/*' \
--timeout 60sexpect exits 0 when a matching event arrives, 7 if none does before the timeout. health --fail-on exits 8 (partial_failure) when the threshold is breached. Treat a clean expect and a clean health as the recovery signal; either non-zero exit means roll forward into diagnosis.
Pause versus disable#
forwarder pause: temporary, queued
Stops delivery but keeps queuing inbound webhooks. Reversible with resume, which drains the backlog. This is the deploy-window primitive. Use it whenever you intend to bring the target back.
forwarder disable: durable stop
forwarder disable -b <slug> -f <name> marks the forwarder inactive so it no longer takes deliveries. Use it to retire a target, not to bracket a deploy. Re-enable it from the dashboard or by recreating the route.
If recovery fails#
A failed recovery check is recoverable. Nothing was lost.
The backlog already drained or is draining. New events keep flowing; you are diagnosing, not firefighting data loss.
Run forwards search --failed and inspect forwards chain for the failing events. See Diagnose webhooks.
Deploy-guard procedure
- Require
writescope (auth status→scopescontainswrite). forwarder pause -b <slug> -f <name> --jsonfor every target forwarder → assert alldata.results[].success == true. Never omit-b/-f(interactive otherwise).- Run the deploy out of band; block on its success.
forwarder resume -b <slug> -f <name> --json→ assert alldata.results[].success == true.- Verify:
expect … --timeout 60s(exit0required) ANDhealth --fail-on '…' --json(exit0required). - On any non-zero verify exit:
forwards search --failed→forwards chain→replaythe failures.