Repository navigation
feat(pathways): pause and resume delivery from the control plane - #112
Merged
Merged
Conversation
Adds `datapumpPause` and `datapumpResume` to the poll-based command queue, and makes the pause durable so a pathway comes back paused at the same position after a restart. `PathwayPump.pause()` / `resume()` stop delivery to the handlers while the pumps keep fetching, keep their buffer, keep their cursor and keep reporting pulses. Requires @flowcore/data-pump 0.23.0. Targets are carried in the existing `sourceFlowTypes` field. A bare `"orders.0"` targets every pump group on that flow type, a composite `"orders.0::hot"` targets exactly one pump. That composite form is already public API — it is the `concurrency.byPumpGroup` key — so pump groups need no new control-plane field. Three gaps are fixed along the way: - `datapumpRestart` silently dropped pump groups. It passed only `sourceFlowTypes` to `reset()`, even though `PumpResetFilter` already accepted `pumpGroups`. - `stopAt` was parsed off the command and then discarded. It now reaches `FlowcoreDataPump.restart(state, stopAt)`. - An unknown command type logged a warning and the poller then reported `running`, so the control plane recorded a success that never happened. Unknown types and filters that match no pump now throw, and are reported as `failed`. The poll response is validated with Zod instead of cast. Everything downstream acts on a live pump, so a malformed `position` would move a cursor and a malformed target list would pause the wrong pathway. Durability comes from a new `PathwayDeliveryStore`, configured with `withPathwayDeliveryStore()`. The default is in memory; `PostgresPathwayDeliveryStore` makes it survive a redeploy, a pod restart and a cluster leader change. The stored pause is applied BEFORE the pumps start, so a restored pathway never delivers a batch on the way up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
0.23.0 adds `pause()`, `resume()` and the `paused` construction option that PathwayPump now calls. On 0.22.1 those methods do not exist, so a pause command would throw at runtime. 0.22.1 also predates the April 2026 lifecycle fix, where a restart resumed the fetch loop but neither the process loop nor the pulse emitter. Pause is a lifecycle change, so it would have wedged the same way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
datapumpPauseanddatapumpResumeto the poll-based command queue, and makes the pause durable so a pathway comes back paused at the same position after a restart.A paused pump keeps fetching, keeps its buffer, keeps its cursor and keeps reporting pulses. Only delivery to the handlers stops, so the control plane still sees a live pathway. A batch already inside a handler finishes and acknowledges.
Targeting needs no new control-plane field
All three commands share one target list, carried in the existing
sourceFlowTypes:"orders.0""orders.0::hot"The composite form is already public API — it is the
concurrency.byPumpGroupkey and the valuereset()returns. A pump group belongs to exactly one flow type, so the pair is the identity and one field carries both levels of precision.Three gaps fixed along the way
datapumpRestartsilently dropped pump groups. It passed onlysourceFlowTypestoreset(), thoughPumpResetFilteralready acceptedpumpGroups. Restart now shares the pause filter.stopAtwas parsed and discarded. It now reachesFlowcoreDataPump.restart(state, stopAt).running, so the control plane recorded a success that never happened. Unknown types and filters matching no pump now throw and reportfailed.Validation
The poll response is validated with Zod instead of cast. Everything downstream acts on a live pump: a malformed
positionwould move a cursor, a malformed target list would pause the wrong pathway.Durability
New
PathwayDeliveryStore, configured withwithPathwayDeliveryStore(). The default is in memory;PostgresPathwayDeliveryStoresurvives a redeploy, a pod restart and a cluster leader change. The stored pause is applied before the pumps start, so a restored pathway never delivers a batch on the way up.Test plan
@flowcore/data-pumpbumped to^0.23.0(blocked, see below)deno fmt --check,deno lint,deno check src/mod.tscleanNew tests cover: target parsing, pause/resume by flow type and by pump group, union targeting, empty-match handling, idempotence, restart honouring pump groups,
stopAtpass-through, unknown-type failure, persistence on pause and resume, a store write failure failing the command, and the Postgres store surviving a new instance.Blocker
This PR must not merge until
@flowcore/data-pump@0.23.0is on npm. The library callspump.pause()andpump.resume(), which do not exist in the currently resolved 0.22.1.The publish is broken in the data-pump repo, and has been since 0.22.1 — 0.22.2, 0.22.3 and 0.23.0 are all tagged on GitHub and absent from npm:
The publish job pinned node 20 and ran— fixed in fix(ci): publish to npm on node 22 data-pump#94.npm install -g npm@latest, failing withEBADENGINEA failed publish could not be re-run— fixed in fix(ci): allow the npm publish to be dispatched manually data-pump#96.npm publishand fails withE404 Not Found - PUT https://registry.npmjs.org/@flowcore%2fdata-pump. The package exists, so a 404 on PUT means the token is expired or no longer has publish rights on the@flowcorescope. This needs a maintainer to rotateNODE_AUTH_TOKEN.