Pause and resume one Site's Lane, with a mandatory expiry #147
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent
Spec #134.
What to build
If a Site is being hammered or is misbehaving, the owner currently has no way to stop its Lane short of a redeploy with the whole poller switched off. This ticket lets them stop asking one Site without stopping the other five. Like Check now, it writes a row the poller reads on its next pass and never commands the poller, so it survives a restart -- a pause is a fact about the Site, not about the process.
The pause row is read at the top of a pass, ahead of the refusal check. A paused Lane records its pass with the paused skip value and sleeps until the expiry. Its Series stay due and unstamped -- the identical state a missing browser leaves them in, so nothing new has to handle it and the queue is intact when the pause lifts: a resumed Lane finds its full queue waiting, because a pause delays work rather than discarding it.
Expiry is mandatory, offered as 1h / 6h / 24h. A pause with no expiry is a silent outage left behind on the one surface whose job is proving the poller is alive. No global runtime pause: the deploy-time poll switch stays the only whole-poller stop, and the case for a runtime one is the case where you already have a shell. Rejected: an indefinite pause, and a wildcard pseudo-row for a global one (a second meaning for the primary key of a six-row table).
Acquisition is unaffected. A Reader's first bookmark of a Series on a paused Site still reads the page -- pausing a Lane must never break somebody adding a Series. Pause governs the Lane only.
On the Lanes page a pause renders as paused, not as stalled -- the owner's own act must not be reported back as a fault -- in patina, as a paused-and-resumes-in phrase, because a deliberate pause is not trouble. The duration select and the pause action live in one bar, and resume replaces them in the same slot. Both actions answer with the freshly rendered Lanes block.
Acceptance criteria
go test ./...greenBlocked by
Merged into
spec-134(branchticket/147-lane-pause, commitcbe0a28).Pause and resume land as
POST /admin/lanes/{site}/pauseand.../resume, both in the route list rather than gating inside themselves, both body-capped, both answering with the freshly rendered Lanes block. Expiry is mandatory and validated against a fixed 1h/6h/24h allow-list; a missing or unoffered duration is a 400, as is an unknown Site. The duration select and Pause live in one bar and Resume replaces them in the same slot.The poller side needed no change: #141's gate already reads the pause ahead of the refusal check. It is now under test - a Lane both paused and inside a refusal backoff records the paused skip value, not the refusing one. Also tested: a paused Lane makes no fetch and leaves its Series due and unstamped, a freshly constructed poller still sees the pause, resume restores the full queue, and a Reader's first bookmark of a Series on a paused Site still reads the page.
Security invariants preserved: parameterised SQL only,
MaxBytesReaderon both form bodies, owner gate inadminRoutes(), generic client errors with detail logged.Review: both axes clean, no findings on the spec axis.
Two non-blocking observations from the implementer, both inherited rather than introduced:
go test ./...green on the merged base.