@kairos-es/feed 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +28 -0
- package/README.md +109 -2
- package/dist/cjs/Feed.js +6 -0
- package/dist/cjs/Feed.js.map +1 -0
- package/dist/cjs/FeedSink.js +54 -0
- package/dist/cjs/FeedSink.js.map +1 -0
- package/dist/cjs/FeedSyncStore.js +10 -0
- package/dist/cjs/FeedSyncStore.js.map +1 -0
- package/dist/cjs/deliver.js +86 -0
- package/dist/cjs/deliver.js.map +1 -0
- package/dist/cjs/errors.js +114 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/identifiers.js +63 -0
- package/dist/cjs/identifiers.js.map +1 -0
- package/dist/cjs/inMemoryFeed.js +328 -0
- package/dist/cjs/inMemoryFeed.js.map +1 -0
- package/dist/cjs/inMemorySink.js +142 -0
- package/dist/cjs/inMemorySink.js.map +1 -0
- package/dist/cjs/index.js +184 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/inspect.js +68 -0
- package/dist/cjs/inspect.js.map +1 -0
- package/dist/cjs/readiness.js +100 -0
- package/dist/cjs/readiness.js.map +1 -0
- package/dist/cjs/reconcile.js +164 -0
- package/dist/cjs/reconcile.js.map +1 -0
- package/dist/cjs/runFeedSync.js +603 -0
- package/dist/cjs/runFeedSync.js.map +1 -0
- package/dist/cjs/tuning.js +60 -0
- package/dist/cjs/tuning.js.map +1 -0
- package/dist/dts-cjs/Feed.d.ts +99 -0
- package/dist/dts-cjs/Feed.d.ts.map +1 -0
- package/dist/dts-cjs/FeedSink.d.ts +189 -0
- package/dist/dts-cjs/FeedSink.d.ts.map +1 -0
- package/dist/dts-cjs/FeedSyncStore.d.ts +281 -0
- package/dist/dts-cjs/FeedSyncStore.d.ts.map +1 -0
- package/dist/dts-cjs/deliver.d.ts +16 -0
- package/dist/dts-cjs/deliver.d.ts.map +1 -0
- package/dist/dts-cjs/errors.d.ts +131 -0
- package/dist/dts-cjs/errors.d.ts.map +1 -0
- package/dist/dts-cjs/identifiers.d.ts +67 -0
- package/dist/dts-cjs/identifiers.d.ts.map +1 -0
- package/dist/dts-cjs/inMemoryFeed.d.ts +32 -0
- package/dist/dts-cjs/inMemoryFeed.d.ts.map +1 -0
- package/dist/dts-cjs/inMemorySink.d.ts +61 -0
- package/dist/dts-cjs/inMemorySink.d.ts.map +1 -0
- package/dist/dts-cjs/index.d.ts +63 -0
- package/dist/dts-cjs/index.d.ts.map +1 -0
- package/dist/dts-cjs/inspect.d.ts +71 -0
- package/dist/dts-cjs/inspect.d.ts.map +1 -0
- package/dist/dts-cjs/package.json +3 -0
- package/dist/dts-cjs/readiness.d.ts +84 -0
- package/dist/dts-cjs/readiness.d.ts.map +1 -0
- package/dist/dts-cjs/reconcile.d.ts +68 -0
- package/dist/dts-cjs/reconcile.d.ts.map +1 -0
- package/dist/dts-cjs/runFeedSync.d.ts +220 -0
- package/dist/dts-cjs/runFeedSync.d.ts.map +1 -0
- package/dist/dts-cjs/tuning.d.ts +40 -0
- package/dist/dts-cjs/tuning.d.ts.map +1 -0
- package/dist/dts-esm/Feed.d.ts +99 -0
- package/dist/dts-esm/Feed.d.ts.map +1 -0
- package/dist/dts-esm/FeedSink.d.ts +189 -0
- package/dist/dts-esm/FeedSink.d.ts.map +1 -0
- package/dist/dts-esm/FeedSyncStore.d.ts +281 -0
- package/dist/dts-esm/FeedSyncStore.d.ts.map +1 -0
- package/dist/dts-esm/deliver.d.ts +16 -0
- package/dist/dts-esm/deliver.d.ts.map +1 -0
- package/dist/dts-esm/errors.d.ts +131 -0
- package/dist/dts-esm/errors.d.ts.map +1 -0
- package/dist/dts-esm/identifiers.d.ts +67 -0
- package/dist/dts-esm/identifiers.d.ts.map +1 -0
- package/dist/dts-esm/inMemoryFeed.d.ts +32 -0
- package/dist/dts-esm/inMemoryFeed.d.ts.map +1 -0
- package/dist/dts-esm/inMemorySink.d.ts +61 -0
- package/dist/dts-esm/inMemorySink.d.ts.map +1 -0
- package/dist/dts-esm/index.d.ts +63 -0
- package/dist/dts-esm/index.d.ts.map +1 -0
- package/dist/dts-esm/inspect.d.ts +71 -0
- package/dist/dts-esm/inspect.d.ts.map +1 -0
- package/dist/dts-esm/package.json +3 -0
- package/dist/dts-esm/readiness.d.ts +84 -0
- package/dist/dts-esm/readiness.d.ts.map +1 -0
- package/dist/dts-esm/reconcile.d.ts +68 -0
- package/dist/dts-esm/reconcile.d.ts.map +1 -0
- package/dist/dts-esm/runFeedSync.d.ts +220 -0
- package/dist/dts-esm/runFeedSync.d.ts.map +1 -0
- package/dist/dts-esm/tuning.d.ts +40 -0
- package/dist/dts-esm/tuning.d.ts.map +1 -0
- package/dist/esm/Feed.js +2 -0
- package/dist/esm/Feed.js.map +1 -0
- package/dist/esm/FeedSink.js +46 -0
- package/dist/esm/FeedSink.js.map +1 -0
- package/dist/esm/FeedSyncStore.js +3 -0
- package/dist/esm/FeedSyncStore.js.map +1 -0
- package/dist/esm/deliver.js +78 -0
- package/dist/esm/deliver.js.map +1 -0
- package/dist/esm/errors.js +98 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/identifiers.js +56 -0
- package/dist/esm/identifiers.js.map +1 -0
- package/dist/esm/inMemoryFeed.js +320 -0
- package/dist/esm/inMemoryFeed.js.map +1 -0
- package/dist/esm/inMemorySink.js +134 -0
- package/dist/esm/inMemorySink.js.map +1 -0
- package/dist/esm/index.js +62 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/inspect.js +58 -0
- package/dist/esm/inspect.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/dist/esm/readiness.js +92 -0
- package/dist/esm/readiness.js.map +1 -0
- package/dist/esm/reconcile.js +153 -0
- package/dist/esm/reconcile.js.map +1 -0
- package/dist/esm/runFeedSync.js +595 -0
- package/dist/esm/runFeedSync.js.map +1 -0
- package/dist/esm/tuning.js +51 -0
- package/dist/esm/tuning.js.map +1 -0
- package/package.json +34 -3
- package/src/Feed.ts +111 -0
- package/src/FeedSink.ts +130 -0
- package/src/FeedSyncStore.ts +326 -0
- package/src/deliver.ts +108 -0
- package/src/errors.ts +134 -0
- package/src/identifiers.ts +92 -0
- package/src/inMemoryFeed.ts +582 -0
- package/src/inMemorySink.ts +215 -0
- package/src/index.ts +136 -0
- package/src/inspect.ts +114 -0
- package/src/readiness.ts +137 -0
- package/src/reconcile.ts +224 -0
- package/src/runFeedSync.ts +882 -0
- package/src/tuning.ts +65 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.runFeedSync = void 0;
|
|
7
|
+
var _core = require("@kairos-es/core");
|
|
8
|
+
var _effect = require("effect");
|
|
9
|
+
var _deliver = require("./deliver.js");
|
|
10
|
+
var _errors = require("./errors.js");
|
|
11
|
+
var _FeedSink = require("./FeedSink.js");
|
|
12
|
+
var _identifiers = require("./identifiers.js");
|
|
13
|
+
var _reconcile = require("./reconcile.js");
|
|
14
|
+
var _tuning = require("./tuning.js");
|
|
15
|
+
/**
|
|
16
|
+
* `runFeedSync` — the sync worker: one per feed and sink, holding the lease,
|
|
17
|
+
* copying the feed's rows to the sink and moving its cursor only once the sink
|
|
18
|
+
* confirms them (ADR-0019).
|
|
19
|
+
*
|
|
20
|
+
* ## The lifecycle
|
|
21
|
+
*
|
|
22
|
+
* A worker runs in SESSIONS. A session takes the lease, then loops:
|
|
23
|
+
*
|
|
24
|
+
* 1. Read the cursor and the feed's generation. No cursor, or a cursor at another
|
|
25
|
+
* generation, means the sink holds a copy of something the feed no longer is,
|
|
26
|
+
* so the session RESYNCS (below) and loops.
|
|
27
|
+
* 2. Otherwise it TAILS: the rows after the cursor, through core's generic
|
|
28
|
+
* subscribe machine with `emit: 'page'`, so each page is sent as it is read and
|
|
29
|
+
* the worker holds one page in memory, never the backlog. Each page is checked
|
|
30
|
+
* against the generation first, and so is every poll interval on its own, since
|
|
31
|
+
* a reset that writes nothing yields no page; a generation that moved since the
|
|
32
|
+
* cursor was saved ends the tail, and step 1 sees the mismatch.
|
|
33
|
+
*
|
|
34
|
+
* Every page goes through one delivery: send, park the keys the sink refuses with
|
|
35
|
+
* its reasons, send the rest again, confirm. Then ONE compare-and-set moves the
|
|
36
|
+
* cursor past the whole page and moves the parked list with it — the refused keys
|
|
37
|
+
* parked, every key that was taken unparked — and fenced on the lease holder, so a
|
|
38
|
+
* worker that lost its lease moves nothing. Then tombstones every sink has passed
|
|
39
|
+
* are collected.
|
|
40
|
+
*
|
|
41
|
+
* The rules that sequence keeps, each a consequence of a sink not being
|
|
42
|
+
* transactional:
|
|
43
|
+
*
|
|
44
|
+
* - **The cursor moves only after `confirm`.** A crash between `apply` and
|
|
45
|
+
* `confirm` resends the batch; a sink is idempotent, so that costs a resend and
|
|
46
|
+
* nothing else.
|
|
47
|
+
* - **A refused key does not hold the feed up.** It is parked and the cursor moves
|
|
48
|
+
* past it. It is retried when its row next changes, because a change gives the
|
|
49
|
+
* row a `seq` above the cursor, and it leaves the parked list once it is sent
|
|
50
|
+
* successfully — a tombstone for a parked key included, which is how a refused
|
|
51
|
+
* record that is then deleted stops being parked without anyone acting.
|
|
52
|
+
* - **A retryable failure keeps the cursor.** The session ends, and supervision
|
|
53
|
+
* (below) starts a new one after a back-off no shorter than the sink's
|
|
54
|
+
* `retryAfter`; the new session sends the same page again.
|
|
55
|
+
*
|
|
56
|
+
* ## Resync
|
|
57
|
+
*
|
|
58
|
+
* Every row, page by page from the origin, goes into `resync.begin`'s fresh
|
|
59
|
+
* target; then the generation is checked once more, the target is published over
|
|
60
|
+
* the live copy, and the cursor is saved at the new generation with the parked list
|
|
61
|
+
* REPLACED by the refusals the resync met. Resync progress is held in memory only,
|
|
62
|
+
* so a crash restarts it from the origin, with a new `begin` that drops the
|
|
63
|
+
* half-built target the crash left.
|
|
64
|
+
*
|
|
65
|
+
* ### Waiting for the materialisation
|
|
66
|
+
*
|
|
67
|
+
* The feed's end is not the rebuild's end. After a reset the materialisation
|
|
68
|
+
* replays the log and writes the feed as it goes, so a resync that reaches the
|
|
69
|
+
* feed's last row has reached wherever the replay had got to, and publishing there
|
|
70
|
+
* swaps a complete live copy for a partial one. `readiness.ts` owns that argument.
|
|
71
|
+
* So `runFeedSync` takes an optional `readiness`: asked once as each attempt
|
|
72
|
+
* starts, it hands back a probe, and the attempt does not publish until the probe
|
|
73
|
+
* says the materialisation has caught up. Until then the attempt polls: once per
|
|
74
|
+
* poll interval it checks the generation, abandoning the attempt as stale if a
|
|
75
|
+
* reset moved it again, asks the probe, and reads the feed on from where it left
|
|
76
|
+
* off, loading what the replay wrote meanwhile. The probe is asked BEFORE that
|
|
77
|
+
* read, so the read that follows a `true` sees every row the materialisation had
|
|
78
|
+
* committed by the time it answered, since a feed row commits with the checkpoint
|
|
79
|
+
* that produced it. The lease is still checked immediately before `publish`, and
|
|
80
|
+
* the generation once more just before that, however long the wait was.
|
|
81
|
+
*
|
|
82
|
+
* With no `readiness` the attempt publishes at the feed's end, which is exactly the
|
|
83
|
+
* behaviour above, and search can serve a PARTIAL copy for as long as the replay
|
|
84
|
+
* takes. An in-place rebuild has no publish; there the wait holds the closing
|
|
85
|
+
* reconcile and the cursor save instead, so the reconcile never deletes a record
|
|
86
|
+
* the replay has not reached yet. Without a `readiness` an in-place rebuild
|
|
87
|
+
* reconciles at the feed's end too, and so deletes from the live copy every record
|
|
88
|
+
* the replay had not yet written again; the tail sends each back as the replay
|
|
89
|
+
* reaches it.
|
|
90
|
+
*
|
|
91
|
+
* The wait is UNBOUNDED. A probe that never says yes holds the attempt for good,
|
|
92
|
+
* with no error and no restart, because publishing early is the very failure the
|
|
93
|
+
* wait exists to prevent and no timeout could tell a stuck replay from a long one.
|
|
94
|
+
* It is made visible instead: `inspectFeed` reports the sink `resyncDue` for as long
|
|
95
|
+
* as it lasts, since the cursor stays at the old generation, and every
|
|
96
|
+
* `HELD_WAIT_WARN_POLLS` poll intervals (`tuning.ts`) the attempt logs a warning,
|
|
97
|
+
* "feed sync rebuild held on readiness", with the feed, the sink, the generation,
|
|
98
|
+
* the polls so far and how long it has been held.
|
|
99
|
+
*
|
|
100
|
+
* Each `begin` names a target of its own, never one an earlier attempt used, and
|
|
101
|
+
* that is what bounds a lease lapse here. A worker that has lost its lease can
|
|
102
|
+
* still land one call after the new holder's (`FeedSyncStore.ts` says when). Were
|
|
103
|
+
* the target named after its generation alone, that call could be a `publish` of
|
|
104
|
+
* the NEW holder's half-built target, which then goes on loading into a fresh one
|
|
105
|
+
* holding only the later pages, publishes it, and saves its cursor at the head:
|
|
106
|
+
* whole pages lost, and nothing to bring them back. With a target per attempt, a
|
|
107
|
+
* stale `publish` moves only the stale worker's own target — or fails, retryably,
|
|
108
|
+
* when a newer `begin` has dropped it — and a stale `begin` drops the new holder's
|
|
109
|
+
* target, whose `publish` then fails retryably and whose resync starts again.
|
|
110
|
+
* What a stale `publish` of its own target still costs is `FeedSyncStore.ts`'s to
|
|
111
|
+
* say, with the rest of the lease's window.
|
|
112
|
+
*
|
|
113
|
+
* `begin`, `load`, `apply` and `publish` each run behind `ensureHeld`; `confirm`
|
|
114
|
+
* and a reconcile's key listing change nothing, and do not.
|
|
115
|
+
*
|
|
116
|
+
* Tombstones are sent as deletes, although the target starts empty. The feed does
|
|
117
|
+
* not stand still while a resync pages through it: a key loaded on an early page
|
|
118
|
+
* can be deleted by the read model before the resync is done, and its tombstone
|
|
119
|
+
* then sits at a `seq` a LATER page reads. Dropping it would load the key, save
|
|
120
|
+
* the cursor past its delete, and publish a target that holds a record the feed no
|
|
121
|
+
* longer has, with nothing ever coming to remove it. A tombstone for a key the
|
|
122
|
+
* target never held costs a send and changes nothing, since a delete of an absent
|
|
123
|
+
* key is a no-op by the sink laws.
|
|
124
|
+
*
|
|
125
|
+
* The same movement decides the parked list. A key can be met more than once in
|
|
126
|
+
* one resync — refused on an early page, then changed and met again later — so
|
|
127
|
+
* the list saved is what each key's LAST change in the resync came to: parked if
|
|
128
|
+
* that change was refused, absent if it was taken. Keeping every refusal the
|
|
129
|
+
* resync met would leave parked a key the target holds, or one the feed deleted.
|
|
130
|
+
*
|
|
131
|
+
* A sink with no `resync` is resynced IN PLACE: every row is sent to the live copy,
|
|
132
|
+
* live rows as upserts and tombstones as deletes, and then a reconcile deletes what
|
|
133
|
+
* the feed no longer holds. The live copy serves a mixture of old and new from the
|
|
134
|
+
* first page on, which is the price of a target with no atomic swap. Its refusals
|
|
135
|
+
* land in the parked list it saves like any resync's, with two consequences of
|
|
136
|
+
* writing over the live copy: a refused upsert leaves the PREVIOUS generation's
|
|
137
|
+
* document of that key live, and an orphan whose delete the closing reconcile was
|
|
138
|
+
* refused stays live too. Both are parked with the sink's reason, the orphan at the
|
|
139
|
+
* origin `seq` since it has no row, and the closing reconcile's report goes to
|
|
140
|
+
* `onReconcile` like a scheduled one's. A sink with neither part could never be
|
|
141
|
+
* rebuilt, and is refused at construction.
|
|
142
|
+
*
|
|
143
|
+
* ## Supervision
|
|
144
|
+
*
|
|
145
|
+
* Every failure a session meets ends it, and the worker's own loop decides what
|
|
146
|
+
* next. It follows `@kairos-es/automation`'s daemon rather than generalising the
|
|
147
|
+
* read side's supervisor, whose own doc says a progress signal the caller owns does
|
|
148
|
+
* not qualify — and the signal here, a cursor advance, is the worker's own.
|
|
149
|
+
*
|
|
150
|
+
* - `LeaseHeld`: another worker is running. This one waits a poll interval and
|
|
151
|
+
* tries again, and the wait is not a failure: a standby worker is a healthy one,
|
|
152
|
+
* and it takes over within a poll interval of the first worker's lease going.
|
|
153
|
+
* - Anything else: a back-off of `restartMinDelay` doubling to `restartMaxDelay`,
|
|
154
|
+
* scaled by a jitter drawn from `Random` so a fleet of workers does not retry in
|
|
155
|
+
* lockstep, and never shorter than a `SinkRetryable`'s `retryAfter`. A restart
|
|
156
|
+
* that follows no cursor advance since the previous restart counts towards
|
|
157
|
+
* `maxNoProgressRestarts`; reaching it ends the worker with `FeedSyncStalled`,
|
|
158
|
+
* for the caller to report. Any advance resets the count and the curve.
|
|
159
|
+
*
|
|
160
|
+
* Defects are not caught: they are bugs, in the driver or in a sink or store that
|
|
161
|
+
* should have classified its fault, and supervision must not retry a bug.
|
|
162
|
+
*
|
|
163
|
+
* ## The scope
|
|
164
|
+
*
|
|
165
|
+
* The worker never returns. Run it in a fibre of its own beside the projections,
|
|
166
|
+
* and close the scope to stop it: each session runs in a child scope of the
|
|
167
|
+
* caller's, so closing the caller's scope releases the lease.
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
/** The tail's signal that the generation moved under it. Never leaves a session. */
|
|
171
|
+
class GenerationMoved extends /*#__PURE__*/_effect.Data.TaggedError('GenerationMoved') {}
|
|
172
|
+
/** The jitter range applied to every restart back-off. */
|
|
173
|
+
const JITTER_LOW = 0.8;
|
|
174
|
+
const JITTER_HIGH = 1.2;
|
|
175
|
+
/**
|
|
176
|
+
* Run the sync worker for `options.source` and `options.sink`; see the module doc.
|
|
177
|
+
* Dies at once, before taking the lease, on a sink that has neither `resync` nor
|
|
178
|
+
* `reconcile`, on a `reconcileEvery` for a sink with no `reconcile`, and on tuning
|
|
179
|
+
* that is out of range.
|
|
180
|
+
*/
|
|
181
|
+
const runFeedSync = options => _effect.Effect.gen(function* () {
|
|
182
|
+
const config = yield* _effect.Effect.sync(() => resolveOptions(options));
|
|
183
|
+
const parent = yield* _effect.Effect.scope;
|
|
184
|
+
const progress = yield* _effect.Ref.make(0);
|
|
185
|
+
const id = {
|
|
186
|
+
feed: options.source.feed,
|
|
187
|
+
sink: options.sink.name
|
|
188
|
+
};
|
|
189
|
+
let seen = 0;
|
|
190
|
+
let restarts = 0;
|
|
191
|
+
for (;;) {
|
|
192
|
+
const child = yield* _effect.Scope.fork(parent);
|
|
193
|
+
const failure = yield* _effect.Effect.flip(session(options, config, progress).pipe(_effect.Scope.use(child)));
|
|
194
|
+
if (failure._tag === 'LeaseHeld') {
|
|
195
|
+
yield* _effect.Effect.sleep(config.pollInterval);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const advanced = yield* _effect.Ref.get(progress);
|
|
199
|
+
if (advanced !== seen) {
|
|
200
|
+
seen = advanced;
|
|
201
|
+
restarts = 0;
|
|
202
|
+
}
|
|
203
|
+
restarts += 1;
|
|
204
|
+
if (restarts >= config.maxNoProgressRestarts) {
|
|
205
|
+
yield* _effect.Effect.logError('feed sync stalled', {
|
|
206
|
+
feed: id.feed,
|
|
207
|
+
sink: id.sink,
|
|
208
|
+
restarts,
|
|
209
|
+
reason: String(failure)
|
|
210
|
+
});
|
|
211
|
+
return yield* new _errors.FeedSyncStalled({
|
|
212
|
+
...id,
|
|
213
|
+
restarts,
|
|
214
|
+
reason: failure
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
const backoff = yield* restartDelay(config, restarts);
|
|
218
|
+
const delay = failure._tag === 'SinkRetryable' && failure.retryAfter !== undefined ? _effect.Duration.max(backoff, failure.retryAfter) : backoff;
|
|
219
|
+
yield* _effect.Effect.logWarning('feed sync restarting', {
|
|
220
|
+
feed: id.feed,
|
|
221
|
+
sink: id.sink,
|
|
222
|
+
restarts,
|
|
223
|
+
delayMillis: _effect.Duration.toMillis(delay),
|
|
224
|
+
reason: String(failure)
|
|
225
|
+
});
|
|
226
|
+
if (config.onRestart !== undefined) {
|
|
227
|
+
yield* config.onRestart({
|
|
228
|
+
...id,
|
|
229
|
+
restarts,
|
|
230
|
+
delay,
|
|
231
|
+
reason: failure
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
yield* _effect.Effect.sleep(delay);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
exports.runFeedSync = runFeedSync;
|
|
238
|
+
const resolveOptions = options => {
|
|
239
|
+
const where = `runFeedSync(feed '${options.source.feed}', sink '${options.sink.name}')`;
|
|
240
|
+
const {
|
|
241
|
+
resync,
|
|
242
|
+
reconcile
|
|
243
|
+
} = options.sink;
|
|
244
|
+
const rebuild = rebuildOf(where, resync, reconcile);
|
|
245
|
+
if (options.reconcileEvery !== undefined && reconcile === undefined) {
|
|
246
|
+
throw new Error(`${where}: reconcileEvery is set, and the sink has no reconcile`);
|
|
247
|
+
}
|
|
248
|
+
const tuning = options.tuning ?? {};
|
|
249
|
+
const pageSize = tuning.pageSize ?? _tuning.DEFAULT_FEED_PAGE_SIZE;
|
|
250
|
+
const limit = (0, _tuning.readLimit)(pageSize);
|
|
251
|
+
const maxNoProgressRestarts = tuning.maxNoProgressRestarts ?? _tuning.DEFAULT_FEED_MAX_NO_PROGRESS_RESTARTS;
|
|
252
|
+
if (!Number.isInteger(maxNoProgressRestarts) || maxNoProgressRestarts <= 0) {
|
|
253
|
+
throw new Error(`${where}: maxNoProgressRestarts must be a positive integer`);
|
|
254
|
+
}
|
|
255
|
+
const pollInterval = (0, _tuning.positiveDuration)('pollInterval', tuning.pollInterval ?? _tuning.DEFAULT_FEED_POLL_INTERVAL);
|
|
256
|
+
const restartMinDelay = (0, _tuning.positiveDuration)('restartMinDelay', tuning.restartMinDelay ?? _tuning.DEFAULT_FEED_RESTART_MIN_DELAY);
|
|
257
|
+
const restartMaxDelay = (0, _tuning.positiveDuration)('restartMaxDelay', tuning.restartMaxDelay ?? _tuning.DEFAULT_FEED_RESTART_MAX_DELAY);
|
|
258
|
+
return {
|
|
259
|
+
pollInterval,
|
|
260
|
+
pageSize,
|
|
261
|
+
limit,
|
|
262
|
+
restartMinDelay,
|
|
263
|
+
restartMaxDelay,
|
|
264
|
+
maxNoProgressRestarts,
|
|
265
|
+
onRestart: tuning.onRestart,
|
|
266
|
+
onReconcile: tuning.onReconcile,
|
|
267
|
+
rebuild,
|
|
268
|
+
periodic: options.reconcileEvery === undefined || reconcile === undefined ? _effect.Option.none() : _effect.Option.some({
|
|
269
|
+
every: (0, _tuning.positiveDuration)('reconcileEvery', options.reconcileEvery),
|
|
270
|
+
reconcile
|
|
271
|
+
}),
|
|
272
|
+
readiness: _effect.Option.fromUndefinedOr(options.readiness)
|
|
273
|
+
};
|
|
274
|
+
};
|
|
275
|
+
/** The sink's {@link Rebuild}, refusing a sink that could never be rebuilt. */
|
|
276
|
+
const rebuildOf = (where, resync, reconcile) => {
|
|
277
|
+
if (resync !== undefined) {
|
|
278
|
+
return {
|
|
279
|
+
_tag: 'Swap',
|
|
280
|
+
resync
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
if (reconcile !== undefined) {
|
|
284
|
+
return {
|
|
285
|
+
_tag: 'InPlace',
|
|
286
|
+
reconcile
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
throw new Error(`${where}: the sink has neither resync nor reconcile, so it could never be rebuilt after a reset`);
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* The delay before restart `n` (1-based): `min(cap, min × 2^(n-1))`, scaled by a
|
|
293
|
+
* jitter drawn from `Random`, so a seeded `Random` makes it repeat.
|
|
294
|
+
*/
|
|
295
|
+
const restartDelay = (config, n) => _effect.Effect.map(_effect.Random.nextBetween(JITTER_LOW, JITTER_HIGH), jitter => {
|
|
296
|
+
const raw = _effect.Duration.toMillis(config.restartMinDelay) * 2 ** (n - 1);
|
|
297
|
+
const capped = Math.min(raw, _effect.Duration.toMillis(config.restartMaxDelay));
|
|
298
|
+
return _effect.Duration.millis(Math.round(capped * jitter));
|
|
299
|
+
});
|
|
300
|
+
/**
|
|
301
|
+
* Read the feed's generation and say whether it is still `held`. The ONE place the
|
|
302
|
+
* driver asks whether a reset has happened: before choosing to tail or resync, per
|
|
303
|
+
* tail page, per poll interval of the tail's watch, per poll interval of a resync
|
|
304
|
+
* waiting on its readiness, and before a resync publishes.
|
|
305
|
+
* A `held` of `None` — no cursor yet — counts as moved, since the sink then holds
|
|
306
|
+
* a copy of no generation at all.
|
|
307
|
+
*/
|
|
308
|
+
const checkGeneration = (source, held) => _effect.Effect.map(source.generation, current => ({
|
|
309
|
+
current,
|
|
310
|
+
moved: _effect.Option.isNone(held) || held.value !== current
|
|
311
|
+
}));
|
|
312
|
+
const makeSessionContext = (options, config, progress, lease) => {
|
|
313
|
+
const {
|
|
314
|
+
source,
|
|
315
|
+
sink,
|
|
316
|
+
store
|
|
317
|
+
} = options;
|
|
318
|
+
return {
|
|
319
|
+
source,
|
|
320
|
+
sink,
|
|
321
|
+
config,
|
|
322
|
+
lease,
|
|
323
|
+
deliverRows: (send, rows) => (0, _deliver.deliver)({
|
|
324
|
+
send,
|
|
325
|
+
confirm: sink.confirm,
|
|
326
|
+
lease,
|
|
327
|
+
pending: _effect.Array.map(rows, row => ({
|
|
328
|
+
change: (0, _FeedSink.changeOf)(row),
|
|
329
|
+
seq: row.seq
|
|
330
|
+
}))
|
|
331
|
+
}),
|
|
332
|
+
advance: args => _effect.Effect.gen(function* () {
|
|
333
|
+
yield* store.casCursor({
|
|
334
|
+
feed: source.feed,
|
|
335
|
+
sink: sink.name,
|
|
336
|
+
holder: lease.holder,
|
|
337
|
+
expected: args.expected,
|
|
338
|
+
next: args.next,
|
|
339
|
+
parked: args.parked
|
|
340
|
+
});
|
|
341
|
+
yield* _effect.Ref.update(progress, n => n + 1);
|
|
342
|
+
yield* store.collectTombstones(source.feed);
|
|
343
|
+
}),
|
|
344
|
+
unparkGone: isGone => (0, _reconcile.unparkGone)(store, {
|
|
345
|
+
feed: source.feed,
|
|
346
|
+
sink: sink.name
|
|
347
|
+
}, isGone),
|
|
348
|
+
reconcile: reconcile => (0, _reconcile.reconcileWith)({
|
|
349
|
+
source,
|
|
350
|
+
sink,
|
|
351
|
+
reconcile,
|
|
352
|
+
lease,
|
|
353
|
+
pageSize: config.pageSize
|
|
354
|
+
})
|
|
355
|
+
};
|
|
356
|
+
};
|
|
357
|
+
/** One session: the lease, then resync or tail, forever, until something fails. */
|
|
358
|
+
const session = (options, config, progress) => _effect.Effect.gen(function* () {
|
|
359
|
+
const id = {
|
|
360
|
+
feed: options.source.feed,
|
|
361
|
+
sink: options.sink.name
|
|
362
|
+
};
|
|
363
|
+
const lease = yield* options.store.acquireLease(id);
|
|
364
|
+
const ctx = makeSessionContext(options, config, progress, lease);
|
|
365
|
+
const step = _effect.Effect.gen(function* () {
|
|
366
|
+
const cursor = yield* options.store.readCursor(id);
|
|
367
|
+
const check = yield* checkGeneration(ctx.source, _effect.Option.map(cursor, c => c.generation));
|
|
368
|
+
if (_effect.Option.isSome(cursor) && !check.moved) {
|
|
369
|
+
return yield* tail(ctx, cursor.value).pipe(_effect.Effect.catchTag('GenerationMoved', () => _effect.Effect.void));
|
|
370
|
+
}
|
|
371
|
+
return yield* resync(ctx, {
|
|
372
|
+
generation: check.current,
|
|
373
|
+
previous: cursor
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
return yield* _effect.Effect.forever(step);
|
|
377
|
+
});
|
|
378
|
+
/** The tail: pages after the cursor, each delivered then advanced past. */
|
|
379
|
+
const tail = (ctx, start) => _effect.Effect.gen(function* () {
|
|
380
|
+
const {
|
|
381
|
+
source,
|
|
382
|
+
sink,
|
|
383
|
+
config
|
|
384
|
+
} = ctx;
|
|
385
|
+
const current = yield* _effect.Ref.make(start);
|
|
386
|
+
// Fails `GenerationMoved` once the feed has left the cursor's generation.
|
|
387
|
+
const ensureGeneration = _effect.Effect.gen(function* () {
|
|
388
|
+
const cursor = yield* _effect.Ref.get(current);
|
|
389
|
+
const check = yield* checkGeneration(source, _effect.Option.some(cursor.generation));
|
|
390
|
+
if (check.moved) {
|
|
391
|
+
return yield* new GenerationMoved();
|
|
392
|
+
}
|
|
393
|
+
return cursor;
|
|
394
|
+
});
|
|
395
|
+
const onPage = rows => _effect.Effect.gen(function* () {
|
|
396
|
+
const cursor = yield* ensureGeneration;
|
|
397
|
+
const delivered = yield* ctx.deliverRows(sink.apply, rows);
|
|
398
|
+
const next = {
|
|
399
|
+
generation: cursor.generation,
|
|
400
|
+
seq: _effect.Array.lastNonEmpty(rows).seq
|
|
401
|
+
};
|
|
402
|
+
yield* ctx.advance({
|
|
403
|
+
expected: _effect.Option.some(cursor),
|
|
404
|
+
next,
|
|
405
|
+
parked: {
|
|
406
|
+
_tag: 'Amend',
|
|
407
|
+
park: delivered.parked,
|
|
408
|
+
unpark: delivered.sent
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
yield* _effect.Ref.set(current, next);
|
|
412
|
+
});
|
|
413
|
+
// A periodic reconcile parks nothing of its own: an orphan it could not delete
|
|
414
|
+
// is still in the copy, so the next period finds it and tries again, and the
|
|
415
|
+
// report says so meanwhile. What it does owe the parked list is every park of a
|
|
416
|
+
// key now gone from the sink, or `inspectFeed` would go on reporting a refusal
|
|
417
|
+
// for a record that is no longer there; `unparkGone` says why its failure only
|
|
418
|
+
// warns.
|
|
419
|
+
const onReconcile = reconcile => _effect.Effect.gen(function* () {
|
|
420
|
+
const {
|
|
421
|
+
report,
|
|
422
|
+
isGone
|
|
423
|
+
} = yield* ctx.reconcile(reconcile);
|
|
424
|
+
if (config.onReconcile !== undefined) {
|
|
425
|
+
yield* config.onReconcile(report);
|
|
426
|
+
}
|
|
427
|
+
yield* ctx.unparkGone(isGone);
|
|
428
|
+
});
|
|
429
|
+
const pages = (0, _core.subscribeItems)({
|
|
430
|
+
fetch: source.changesAfter,
|
|
431
|
+
cursorOf: row => row.seq,
|
|
432
|
+
initial: start.seq,
|
|
433
|
+
...(source.listen === undefined ? {} : {
|
|
434
|
+
listen: source.listen
|
|
435
|
+
}),
|
|
436
|
+
pollInterval: _effect.Duration.toMillis(config.pollInterval),
|
|
437
|
+
catchUpPageSize: config.pageSize,
|
|
438
|
+
emit: 'page'
|
|
439
|
+
}).pipe(_effect.Stream.chunks, _effect.Stream.map(rows => ({
|
|
440
|
+
_tag: 'Page',
|
|
441
|
+
rows
|
|
442
|
+
})));
|
|
443
|
+
// A reset that writes no row would otherwise go unseen: the tail checks the
|
|
444
|
+
// generation per PAGE, and an emptied feed yields no page. So the generation is
|
|
445
|
+
// also read once per poll interval on its own, and a move ends the tail.
|
|
446
|
+
const generationWatch = _effect.Stream.tick(config.pollInterval).pipe(_effect.Stream.drop(1), _effect.Stream.as({
|
|
447
|
+
_tag: 'Watch'
|
|
448
|
+
}));
|
|
449
|
+
const reconcileTicks = _effect.Option.match(config.periodic, {
|
|
450
|
+
onNone: () => _effect.Stream.empty,
|
|
451
|
+
onSome: ({
|
|
452
|
+
every,
|
|
453
|
+
reconcile
|
|
454
|
+
}) => _effect.Stream.tick(every).pipe(
|
|
455
|
+
// `tick` fires once at the start; a reconcile is due one period in.
|
|
456
|
+
_effect.Stream.drop(1), _effect.Stream.as({
|
|
457
|
+
_tag: 'Reconcile',
|
|
458
|
+
reconcile
|
|
459
|
+
}))
|
|
460
|
+
});
|
|
461
|
+
// One consumer, so a page, a watch and a reconcile never overlap: nothing else
|
|
462
|
+
// sends while a reconcile runs, which is what lets it run under this lease.
|
|
463
|
+
yield* _effect.Stream.runForEach(_effect.Stream.merge(pages, _effect.Stream.merge(generationWatch, reconcileTicks)), event => event._tag === 'Page' ? onPage(event.rows) : event._tag === 'Watch' ? _effect.Effect.asVoid(ensureGeneration) : onReconcile(event.reconcile));
|
|
464
|
+
});
|
|
465
|
+
/** What a swap's `publish` sent: no record at all. */
|
|
466
|
+
const NOTHING_SENT = {
|
|
467
|
+
sent: [],
|
|
468
|
+
parked: []
|
|
469
|
+
};
|
|
470
|
+
const startRebuild = (ctx, generation) => {
|
|
471
|
+
const {
|
|
472
|
+
rebuild
|
|
473
|
+
} = ctx.config;
|
|
474
|
+
if (rebuild._tag === 'InPlace') {
|
|
475
|
+
return _effect.Effect.succeed({
|
|
476
|
+
send: ctx.sink.apply,
|
|
477
|
+
finish: _effect.Effect.gen(function* () {
|
|
478
|
+
const {
|
|
479
|
+
report
|
|
480
|
+
} = yield* ctx.reconcile(rebuild.reconcile);
|
|
481
|
+
if (ctx.config.onReconcile !== undefined) {
|
|
482
|
+
yield* ctx.config.onReconcile(report);
|
|
483
|
+
}
|
|
484
|
+
// An orphan has no row, so its park carries the origin as its `seq`: there
|
|
485
|
+
// is no change of it to point at, and `retryParked` on a key with no row
|
|
486
|
+
// simply unparks it.
|
|
487
|
+
const parkedAt = yield* _effect.DateTime.now;
|
|
488
|
+
return {
|
|
489
|
+
sent: report.deleted,
|
|
490
|
+
parked: report.refused.map(({
|
|
491
|
+
key,
|
|
492
|
+
reason
|
|
493
|
+
}) => ({
|
|
494
|
+
key,
|
|
495
|
+
seq: _identifiers.FEED_ORIGIN,
|
|
496
|
+
reason,
|
|
497
|
+
parkedAt
|
|
498
|
+
}))
|
|
499
|
+
};
|
|
500
|
+
})
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
const {
|
|
504
|
+
resync
|
|
505
|
+
} = rebuild;
|
|
506
|
+
return _effect.Effect.gen(function* () {
|
|
507
|
+
// `begin` destroys: it empties a target and drops every other one, which can
|
|
508
|
+
// be the half-built target of the worker that holds the lease now. So it is a
|
|
509
|
+
// send like any other, and runs only under a lease just seen held.
|
|
510
|
+
yield* ctx.lease.ensureHeld;
|
|
511
|
+
const target = yield* resync.begin(generation);
|
|
512
|
+
return {
|
|
513
|
+
send: batch => resync.load(target, batch),
|
|
514
|
+
finish: _effect.Effect.as(_effect.Effect.andThen(ctx.lease.ensureHeld, resync.publish(target)), NOTHING_SENT)
|
|
515
|
+
};
|
|
516
|
+
});
|
|
517
|
+
};
|
|
518
|
+
/** Always ready: the probe of a worker given no `readiness`. */
|
|
519
|
+
const ALWAYS_READY = /*#__PURE__*/_effect.Effect.succeed(true);
|
|
520
|
+
/** A full resync at `generation`; see the module doc. */
|
|
521
|
+
const resync = (ctx, at) => _effect.Effect.gen(function* () {
|
|
522
|
+
const {
|
|
523
|
+
source,
|
|
524
|
+
config
|
|
525
|
+
} = ctx;
|
|
526
|
+
// Asked before anything is read, so the point the probe judges by is fixed
|
|
527
|
+
// before the first page: see the module doc's "Waiting for the materialisation".
|
|
528
|
+
const ready = yield* _effect.Option.match(config.readiness, {
|
|
529
|
+
onNone: () => _effect.Effect.succeed(ALWAYS_READY),
|
|
530
|
+
onSome: readiness => readiness(at.generation)
|
|
531
|
+
});
|
|
532
|
+
const rebuilding = yield* startRebuild(ctx, at.generation);
|
|
533
|
+
const stale = _effect.Effect.map(checkGeneration(source, _effect.Option.some(at.generation)), check => check.moved);
|
|
534
|
+
// By key, so a later page's outcome for a key replaces an earlier one's: the
|
|
535
|
+
// list saved is what each key's LAST change in this resync came to.
|
|
536
|
+
const parked = new Map();
|
|
537
|
+
const settle = delivered => {
|
|
538
|
+
for (const sent of delivered.sent) {
|
|
539
|
+
parked.delete(sent);
|
|
540
|
+
}
|
|
541
|
+
for (const record of delivered.parked) {
|
|
542
|
+
parked.set(record.key, record);
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
let last = _identifiers.FEED_ORIGIN;
|
|
546
|
+
const heldSince = yield* _effect.Clock.currentTimeMillis;
|
|
547
|
+
let polls = 0;
|
|
548
|
+
for (;;) {
|
|
549
|
+
// Before the read, so a `true` covers every row the read then finds.
|
|
550
|
+
const caughtUp = yield* ready;
|
|
551
|
+
for (;;) {
|
|
552
|
+
const rows = yield* source.changesAfter(last, config.limit);
|
|
553
|
+
if (!_effect.Array.isReadonlyArrayNonEmpty(rows)) {
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
// Tombstones included: see the module doc's Resync section.
|
|
557
|
+
settle(yield* ctx.deliverRows(rebuilding.send, rows));
|
|
558
|
+
last = _effect.Array.lastNonEmpty(rows).seq;
|
|
559
|
+
if (rows.length < config.pageSize) {
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (caughtUp) {
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
yield* _effect.Effect.sleep(config.pollInterval);
|
|
567
|
+
if (yield* stale) {
|
|
568
|
+
// Reset again while this waited: abandon the attempt, as below.
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
polls += 1;
|
|
572
|
+
// The wait has no bound — see the module doc — so a probe that never says
|
|
573
|
+
// yes must at least be seen not to. Every string or number, never a bigint,
|
|
574
|
+
// so a logger that JSON-encodes the line keeps it.
|
|
575
|
+
if (polls % _tuning.HELD_WAIT_WARN_POLLS === 0) {
|
|
576
|
+
yield* _effect.Effect.logWarning('feed sync rebuild held on readiness', {
|
|
577
|
+
feed: source.feed,
|
|
578
|
+
sink: ctx.sink.name,
|
|
579
|
+
generation: String(at.generation),
|
|
580
|
+
polls,
|
|
581
|
+
heldMillis: (yield* _effect.Clock.currentTimeMillis) - heldSince
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (yield* stale) {
|
|
586
|
+
// Reset again while this ran: what was loaded is already stale. Leave the
|
|
587
|
+
// cursor alone, and the session's next step starts the resync over.
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
settle(yield* rebuilding.finish);
|
|
591
|
+
yield* ctx.advance({
|
|
592
|
+
expected: at.previous,
|
|
593
|
+
next: {
|
|
594
|
+
generation: at.generation,
|
|
595
|
+
seq: last
|
|
596
|
+
},
|
|
597
|
+
parked: {
|
|
598
|
+
_tag: 'Replace',
|
|
599
|
+
park: Array.from(parked.values())
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
//# sourceMappingURL=runFeedSync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runFeedSync.js","names":["_core","require","_effect","_deliver","_errors","_FeedSink","_identifiers","_reconcile","_tuning","GenerationMoved","Data","TaggedError","JITTER_LOW","JITTER_HIGH","runFeedSync","options","Effect","gen","config","sync","resolveOptions","parent","scope","progress","Ref","make","id","feed","source","sink","name","seen","restarts","child","Scope","fork","failure","flip","session","pipe","use","_tag","sleep","pollInterval","advanced","get","maxNoProgressRestarts","logError","reason","String","FeedSyncStalled","backoff","restartDelay","delay","retryAfter","undefined","Duration","max","logWarning","delayMillis","toMillis","onRestart","exports","where","resync","reconcile","rebuild","rebuildOf","reconcileEvery","Error","tuning","pageSize","DEFAULT_FEED_PAGE_SIZE","limit","readLimit","DEFAULT_FEED_MAX_NO_PROGRESS_RESTARTS","Number","isInteger","positiveDuration","DEFAULT_FEED_POLL_INTERVAL","restartMinDelay","DEFAULT_FEED_RESTART_MIN_DELAY","restartMaxDelay","DEFAULT_FEED_RESTART_MAX_DELAY","onReconcile","periodic","Option","none","some","every","readiness","fromUndefinedOr","n","map","Random","nextBetween","jitter","raw","capped","Math","min","millis","round","checkGeneration","held","generation","current","moved","isNone","value","makeSessionContext","lease","store","deliverRows","send","rows","deliver","confirm","pending","Arr","row","change","changeOf","seq","advance","args","casCursor","holder","expected","next","parked","update","collectTombstones","unparkGone","isGone","reconcileWith","acquireLease","ctx","step","cursor","readCursor","check","c","isSome","tail","catchTag","void","previous","forever","start","ensureGeneration","onPage","delivered","apply","lastNonEmpty","park","unpark","sent","set","report","pages","subscribeItems","fetch","changesAfter","cursorOf","initial","listen","catchUpPageSize","emit","Stream","chunks","generationWatch","tick","drop","as","reconcileTicks","match","onNone","empty","onSome","runForEach","merge","event","asVoid","NOTHING_SENT","startRebuild","succeed","finish","parkedAt","DateTime","now","deleted","refused","key","FEED_ORIGIN","ensureHeld","target","begin","batch","load","andThen","publish","ALWAYS_READY","at","ready","rebuilding","stale","Map","settle","delete","record","last","heldSince","Clock","currentTimeMillis","polls","caughtUp","isReadonlyArrayNonEmpty","length","HELD_WAIT_WARN_POLLS","heldMillis","Array","from","values"],"sources":["../../src/runFeedSync.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|