@kairos-es/read 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 +538 -0
- package/dist/cjs/EventLogDurability.js +184 -0
- package/dist/cjs/EventLogDurability.js.map +1 -0
- package/dist/cjs/ProjectionRunner.js +478 -0
- package/dist/cjs/ProjectionRunner.js.map +1 -0
- package/dist/cjs/ProjectionStore.js +233 -0
- package/dist/cjs/ProjectionStore.js.map +1 -0
- package/dist/cjs/foldIntoRef.js +36 -0
- package/dist/cjs/foldIntoRef.js.map +1 -0
- package/dist/cjs/inMemoryProjectionStore.js +138 -0
- package/dist/cjs/inMemoryProjectionStore.js.map +1 -0
- package/dist/cjs/index.js +128 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/projectionWiringFault.js +532 -0
- package/dist/cjs/projectionWiringFault.js.map +1 -0
- package/dist/cjs/runProjection.js +117 -0
- package/dist/cjs/runProjection.js.map +1 -0
- package/dist/cjs/runProjections.js +144 -0
- package/dist/cjs/runProjections.js.map +1 -0
- package/dist/cjs/superviseOnProgress.js +580 -0
- package/dist/cjs/superviseOnProgress.js.map +1 -0
- package/dist/cjs/testing.js +143 -0
- package/dist/cjs/testing.js.map +1 -0
- package/dist/dts/EventLogDurability.d.ts +182 -0
- package/dist/dts/EventLogDurability.d.ts.map +1 -0
- package/dist/dts/ProjectionRunner.d.ts +557 -0
- package/dist/dts/ProjectionRunner.d.ts.map +1 -0
- package/dist/dts/ProjectionStore.d.ts +475 -0
- package/dist/dts/ProjectionStore.d.ts.map +1 -0
- package/dist/dts/foldIntoRef.d.ts +39 -0
- package/dist/dts/foldIntoRef.d.ts.map +1 -0
- package/dist/dts/inMemoryProjectionStore.d.ts +11 -0
- package/dist/dts/inMemoryProjectionStore.d.ts.map +1 -0
- package/dist/dts/index.d.ts +185 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/dts/projectionWiringFault.d.ts +260 -0
- package/dist/dts/projectionWiringFault.d.ts.map +1 -0
- package/dist/dts/runProjection.d.ts +185 -0
- package/dist/dts/runProjection.d.ts.map +1 -0
- package/dist/dts/runProjections.d.ts +480 -0
- package/dist/dts/runProjections.d.ts.map +1 -0
- package/dist/dts/superviseOnProgress.d.ts +587 -0
- package/dist/dts/superviseOnProgress.d.ts.map +1 -0
- package/dist/dts/testing.d.ts +207 -0
- package/dist/dts/testing.d.ts.map +1 -0
- package/dist/esm/EventLogDurability.js +175 -0
- package/dist/esm/EventLogDurability.js.map +1 -0
- package/dist/esm/ProjectionRunner.js +468 -0
- package/dist/esm/ProjectionRunner.js.map +1 -0
- package/dist/esm/ProjectionStore.js +223 -0
- package/dist/esm/ProjectionStore.js.map +1 -0
- package/dist/esm/foldIntoRef.js +29 -0
- package/dist/esm/foldIntoRef.js.map +1 -0
- package/dist/esm/inMemoryProjectionStore.js +131 -0
- package/dist/esm/inMemoryProjectionStore.js.map +1 -0
- package/dist/esm/index.js +185 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/dist/esm/projectionWiringFault.js +524 -0
- package/dist/esm/projectionWiringFault.js.map +1 -0
- package/dist/esm/runProjection.js +109 -0
- package/dist/esm/runProjection.js.map +1 -0
- package/dist/esm/runProjections.js +137 -0
- package/dist/esm/runProjections.js.map +1 -0
- package/dist/esm/superviseOnProgress.js +571 -0
- package/dist/esm/superviseOnProgress.js.map +1 -0
- package/dist/esm/testing.js +133 -0
- package/dist/esm/testing.js.map +1 -0
- package/package.json +41 -0
- package/src/EventLogDurability.ts +201 -0
- package/src/ProjectionRunner.ts +923 -0
- package/src/ProjectionStore.ts +528 -0
- package/src/foldIntoRef.ts +63 -0
- package/src/inMemoryProjectionStore.ts +163 -0
- package/src/index.ts +218 -0
- package/src/projectionWiringFault.ts +694 -0
- package/src/runProjection.ts +270 -0
- package/src/runProjections.ts +623 -0
- package/src/superviseOnProgress.ts +897 -0
- package/src/testing.ts +290 -0
- package/testing/package.json +6 -0
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ProjectionRunner` — the read side's daemon: ONE `subscribe(query, checkpoint)`
|
|
3
|
+
* stream per `ReadModel`, decoded through the codec's shared decode stage,
|
|
4
|
+
* micro-batched, committed atomically with its checkpoint, and supervised
|
|
5
|
+
* (ADR-0007).
|
|
6
|
+
*
|
|
7
|
+
* ## The pipeline, and why every stage is the stage it is
|
|
8
|
+
*
|
|
9
|
+
* `subscribe -> decode -> groupedWithin -> mapEffect(commit, concurrency 1) ->
|
|
10
|
+
* runDrain`. Each arrow is a back-pressure boundary, and that is the point: a
|
|
11
|
+
* projection must be able to catch up over a backlog far larger than memory, so
|
|
12
|
+
* nothing in the chain may buffer without bound and nothing may run ahead of the
|
|
13
|
+
* committer.
|
|
14
|
+
*
|
|
15
|
+
* - **`subscribe`, not `read`.** The store's `subscribe` is catch-up-then-live
|
|
16
|
+
* behind one contract, so the runner has no catch-up mode and no live mode and
|
|
17
|
+
* therefore no transition between them to get wrong. It also means the runner
|
|
18
|
+
* never learns which engine it is running against (`store-postgres`'s
|
|
19
|
+
* LISTEN/NOTIFY wake over `core`'s shared poll machine, `store-sqlite`'s
|
|
20
|
+
* unwoken ride on that same poll, or the in-memory layer's `PubSub` wake over
|
|
21
|
+
* the same machine again).
|
|
22
|
+
* - **The codec's `decodeSlices`, not a local copy.** The read side needs exactly
|
|
23
|
+
* the decode stage the write side's own fold needs, so it shares that one
|
|
24
|
+
* implementation; a read-side copy could silently accept an event the decision
|
|
25
|
+
* path rejects. Decode is deliberately sequential (`Stream.mapEffect` with no
|
|
26
|
+
* `concurrency`), because a fold is order-sensitive and decode order must stay
|
|
27
|
+
* position order.
|
|
28
|
+
* - **`groupedWithin`, not per-event commit.** One transaction per event would
|
|
29
|
+
* pay a round-trip per event on catch-up; one transaction per *window* amortises
|
|
30
|
+
* it while keeping the transaction small. The window is a latency ceiling too:
|
|
31
|
+
* a lone live event waits at most `batchWindow` rather than for a full batch.
|
|
32
|
+
* - **`mapEffect` at concurrency 1.** The single writer. The checkpoint is a
|
|
33
|
+
* scalar guarded compare-and-set, so two batches in flight would race their own
|
|
34
|
+
* read model's cursor — one would lose its guard and the pipeline would restart
|
|
35
|
+
* for nothing. Concurrency 1 also gives the natural back-pressure: the stream
|
|
36
|
+
* pulls the next window only when the previous commit has landed.
|
|
37
|
+
*
|
|
38
|
+
* ## Supervision lives NEXT DOOR, and that is the point
|
|
39
|
+
*
|
|
40
|
+
* `DcbEventStore.subscribe` is `E = never` — a store that cannot serve the live
|
|
41
|
+
* tail *dies*. So the runner's boundary converts DEATH into a typed
|
|
42
|
+
* `PipelineDied` and hands it to a supervisor, because the checkpoint is the
|
|
43
|
+
* recovery mechanism for infrastructure death, not merely crash-restart hygiene:
|
|
44
|
+
* a restart re-reads the stored checkpoint and re-subscribes from it, which is the
|
|
45
|
+
* same code path a cold boot takes.
|
|
46
|
+
*
|
|
47
|
+
* The supervisor itself is `superviseOnProgress`, a module of its own — but this
|
|
48
|
+
* package's own, not a general combinator on offer to anybody (its module doc says
|
|
49
|
+
* why, and records what generalising it would cost). Its whole input from here is
|
|
50
|
+
* the checkpoint key, `readCheckpoint` as a progress signal, the RESOLVED restart
|
|
51
|
+
* tuning and its two hooks (`onRestart` on every restart, `onStalled` once at the
|
|
52
|
+
* give-up); it knows nothing of `subscribe`, decoding, batching, committing or
|
|
53
|
+
* slices, which is what lets it be stated, documented and TESTED on its own terms:
|
|
54
|
+
* retry while an externally observed signal moves, give up when it stops. What that
|
|
55
|
+
* buys the runner is that everything below is one attempt, `runOnce`, with no
|
|
56
|
+
* supervision state threaded through it; what it buys the supervisor is that its
|
|
57
|
+
* subtle parts (the `ORIGIN` seeding, the breaker being consulted before the sleep,
|
|
58
|
+
* the interruption trap on the re-read, the counter resetting on progress, the
|
|
59
|
+
* five-minute default budget) are pinned against a stub rather than through this
|
|
60
|
+
* whole pipeline. Its module doc carries the reasoning, including why a
|
|
61
|
+
* `CheckpointSuperseded` loser resynchronises instead of tripping the breaker.
|
|
62
|
+
*
|
|
63
|
+
* ## The two entry points live NEXT DOOR
|
|
64
|
+
*
|
|
65
|
+
* What this module holds is the SUBSTRATE: the `ProjectionRunner` handle, the two
|
|
66
|
+
* option sets a caller tunes it with, and the three phases every projection call runs
|
|
67
|
+
* — `resolveProjection`, `prepareProjection` (where the construction gate is
|
|
68
|
+
* consulted) and `buildAndFork`. It exports no entry point of its own.
|
|
69
|
+
* `runProjection.ts` is the N = 1 one and `runProjections.ts` the N >= 1 one; both
|
|
70
|
+
* import from here and nothing here imports from either, which is what lets the
|
|
71
|
+
* substrate be read without either caller in view. `runProjection.ts`'s module doc
|
|
72
|
+
* owns the argument for that arrangement.
|
|
73
|
+
*
|
|
74
|
+
* ## Platform-neutral
|
|
75
|
+
*
|
|
76
|
+
* No `node:*`, no `Date`, no host RNG: the batch window and the backoff are
|
|
77
|
+
* Effect `Duration`s scheduled through the `Clock`, and the jitter is Effect's
|
|
78
|
+
* `Random` service, so a test can drive both deterministically.
|
|
79
|
+
*/
|
|
80
|
+
import type { CodecError, RequirementOf, Serializer, SliceProjection } from '@kairos-es/codec';
|
|
81
|
+
import { DcbEventStore, type DecodedEvent, type Query, type SequencedEvent } from '@kairos-es/core';
|
|
82
|
+
import { Array as Arr, type Duration, Effect, type Fiber, Schema, type Scope, Stream } from 'effect';
|
|
83
|
+
import { EventLogDurability } from './EventLogDurability.js';
|
|
84
|
+
import type { CheckpointKey, Durability, KeyedProjectionStore } from './ProjectionStore.js';
|
|
85
|
+
import { type MaterialisationWiring } from './projectionWiringFault.js';
|
|
86
|
+
import { type ProjectionStalled, type ProjectionSupervisionOptions, type ResolvedSupervisionTuning } from './superviseOnProgress.js';
|
|
87
|
+
/**
|
|
88
|
+
* Maximum events per commit: a branded POSITIVE integer.
|
|
89
|
+
*
|
|
90
|
+
* Branded because `batchSize` is the tuning figure whose invalid values are
|
|
91
|
+
* absorbed most quietly. `Stream.groupedWithin(0, window)` does not throw and
|
|
92
|
+
* does not merely under-batch: it emits EMPTY chunks in a tight loop without
|
|
93
|
+
* ever pulling the subscription, so a projection wired with `batchSize: 0`
|
|
94
|
+
* spins a CPU for ever, commits nothing, stays at `ORIGIN`, never fails, never
|
|
95
|
+
* restarts and logs nothing — the exact silent-stall class the supervisor below
|
|
96
|
+
* exists to make loud, arriving by a route the supervisor cannot see (the
|
|
97
|
+
* breaker only counts RESTARTS, and a spinning stream never ends a run). A
|
|
98
|
+
* fractional or `NaN` size is the same mistake by a different route.
|
|
99
|
+
*
|
|
100
|
+
* The SHAPE mirrors core's `ReadLimit` — `Schema.Int`, a bound, a brand, the
|
|
101
|
+
* same fail-at-the-boundary discipline — but deliberately NOT `ReadLimit`
|
|
102
|
+
* itself, which is `>= 0`. Zero is the whole difference between the two: a
|
|
103
|
+
* `read` capped at zero events is a meaningful (if useless) request, whereas a
|
|
104
|
+
* COMMIT of zero events is not a request at all. Reusing `ReadLimit` here would
|
|
105
|
+
* import the one value that has to be rejected.
|
|
106
|
+
*
|
|
107
|
+
* A distinct brand from `MaxNoProgressRestarts` despite the identical
|
|
108
|
+
* refinement, because the two are still writable side by side in one flat
|
|
109
|
+
* options literal, are both bare integers, and differ by an order of magnitude
|
|
110
|
+
* in meaning — nominality is what makes a transposition fail to typecheck rather
|
|
111
|
+
* than silently retune the runner. That the two now tune different mechanisms
|
|
112
|
+
* (this one the pipeline, that one the supervisor) is a second reason for the
|
|
113
|
+
* distinction, not a replacement for the first.
|
|
114
|
+
*
|
|
115
|
+
* Construct with `BatchSize.make(n)`, which throws a `ParseError` at the call
|
|
116
|
+
* site rather than deferring the mistake to the first stream pull.
|
|
117
|
+
*/
|
|
118
|
+
export declare const BatchSize: Schema.brand<Schema.filter<typeof Schema.Int>, "BatchSize">;
|
|
119
|
+
export type BatchSize = typeof BatchSize.Type;
|
|
120
|
+
/**
|
|
121
|
+
* How the PIPELINE is tuned: how much a commit carries, and how long a partial
|
|
122
|
+
* batch waits for company.
|
|
123
|
+
*
|
|
124
|
+
* Separate from `ProjectionSupervisionOptions` because these are dials on a
|
|
125
|
+
* different machine. These two size a TRANSACTION and a latency ceiling, in
|
|
126
|
+
* milliseconds and events, and their consequences are visible within one batch;
|
|
127
|
+
* the supervision figures size a RECOVERY POLICY measured in minutes of outage,
|
|
128
|
+
* and nothing about them is observable until something has already failed.
|
|
129
|
+
* Reading them as one undifferentiated bag is how `maxNoProgressRestarts` gets
|
|
130
|
+
* retuned as though it were a throughput knob.
|
|
131
|
+
*
|
|
132
|
+
* Every figure is a build-time DEFAULT, not a contract: the mechanisms are fixed
|
|
133
|
+
* by ADR-0007, the numbers are judgement calls sized against
|
|
134
|
+
* `@kairos-es/store-postgres`'s own defaults and are meant to be overridden by a
|
|
135
|
+
* deployment that knows its own latency budget (and by tests, which want tiny
|
|
136
|
+
* windows).
|
|
137
|
+
*
|
|
138
|
+
* A judgement call is still not a free choice: zero, negative, fractional and
|
|
139
|
+
* infinite figures are not "aggressive tuning", they are wirings whose failure
|
|
140
|
+
* mode is a hot loop or a permanently frozen view with nothing on any error
|
|
141
|
+
* channel. So this surface fails at its boundary, exactly as `Tag`, `ReadLimit`
|
|
142
|
+
* and `ReadPostgresConfig` do — `BatchSize` is BRANDED, so a bad value is
|
|
143
|
+
* rejected at the caller's own `.make(...)` and a plain integer literal does not
|
|
144
|
+
* compile at all, while `batchWindow` is judged by the read side's construction
|
|
145
|
+
* gate before anything is forked, because `Duration.DurationInput` is a union with
|
|
146
|
+
* no primitive to refine. `projectionWiringFault` carries that reasoning, and
|
|
147
|
+
* judges the supervisor's three restart durations in the same pass under the same
|
|
148
|
+
* rule — one home for the bound, whichever machine the figure tunes.
|
|
149
|
+
*/
|
|
150
|
+
export interface ProjectionPipelineOptions {
|
|
151
|
+
/**
|
|
152
|
+
* Maximum events per commit. Default `256` — half the store's `catchUpPageSize`
|
|
153
|
+
* default, so one transaction stays small while still amortising round-trips
|
|
154
|
+
* across a catch-up. Raise it for throughput, lower it to shrink the
|
|
155
|
+
* transaction (and the amount of work a lost checkpoint guard discards).
|
|
156
|
+
*
|
|
157
|
+
* A branded positive integer: write `BatchSize.make(512)`, not `512`.
|
|
158
|
+
*/
|
|
159
|
+
readonly batchSize?: BatchSize;
|
|
160
|
+
/**
|
|
161
|
+
* How long a partial batch waits before committing anyway. Default
|
|
162
|
+
* `'50 millis'` — an order of magnitude under the store's 1-second
|
|
163
|
+
* `pollInterval`, so batching never dominates end-to-end lag. This is a latency
|
|
164
|
+
* ceiling, not a delay: a full `batchSize` commits immediately.
|
|
165
|
+
*
|
|
166
|
+
* Positive and finite, checked at construction.
|
|
167
|
+
*/
|
|
168
|
+
readonly batchWindow?: Duration.DurationInput;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Everything `runProjection` can be tuned with: the pipeline's two figures plus
|
|
172
|
+
* the supervisor's four and its two hooks.
|
|
173
|
+
*
|
|
174
|
+
* ## Why FLAT, when the two halves are deliberately distinct types
|
|
175
|
+
*
|
|
176
|
+
* A nested `{ pipeline, supervision }` would state the split at every call site,
|
|
177
|
+
* and it was rejected for a reason worth recording. Overriding one figure of a
|
|
178
|
+
* shared tuning constant is the dominant idiom here — `{ ...RUNNER_OPTIONS,
|
|
179
|
+
* batchSize: ONE_PER_BATCH }` appears throughout this repo's tests and examples
|
|
180
|
+
* — and under a nested shape the obvious spelling of that,
|
|
181
|
+
* `{ ...OPTIONS, supervision: { onRestart } }`, SILENTLY DROPS every other
|
|
182
|
+
* supervision figure, because a spread is shallow. That is precisely the class of
|
|
183
|
+
* quiet mis-tuning the branding and the construction-time checks exist to
|
|
184
|
+
* prevent, and a shape that invites it would be paying in silent bugs for a
|
|
185
|
+
* distinction that types can carry for free.
|
|
186
|
+
*
|
|
187
|
+
* So the distinction lives in the TYPES: two documented interfaces a reader (or
|
|
188
|
+
* an IDE) can see the boundary in, one flat object a caller writes. The two are
|
|
189
|
+
* disjoint by construction, and `buildAndFork` splits them by forwarding each half
|
|
190
|
+
* to the machine that reads it — the pipeline's two figures into the stream, and the
|
|
191
|
+
* supervision half into `superviseOnProgress` as one spread of whatever the caller
|
|
192
|
+
* wrote plus the three RESOLVED durations named after it. That second split is
|
|
193
|
+
* carried by types too (`UnresolvedSupervisionOptions` and
|
|
194
|
+
* `ResolvedSupervisionTuning`); the call site says how.
|
|
195
|
+
*/
|
|
196
|
+
export interface ProjectionRunnerOptions extends ProjectionPipelineOptions, ProjectionSupervisionOptions {
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* ONE materialisation's wiring with every default already applied: the bound view,
|
|
200
|
+
* the key and durability read off it, and the five figures that will actually run.
|
|
201
|
+
*
|
|
202
|
+
* This is the RESOLVE phase's whole output, and every field of it is either judged
|
|
203
|
+
* by the construction gate or used by the pipeline below — usually both, which is
|
|
204
|
+
* the point. `batchSize` is the one exception in the other direction: it is BRANDED,
|
|
205
|
+
* so the gate has nothing left to judge, but it is resolved here anyway because a
|
|
206
|
+
* default the pipeline applied for itself would be a figure resolved in a second
|
|
207
|
+
* place.
|
|
208
|
+
*
|
|
209
|
+
* The three restart figures are not restated here: this interface EXTENDS
|
|
210
|
+
* `ResolvedSupervisionTuning`, which is the type `superviseOnProgress` requires and
|
|
211
|
+
* the type `UnresolvedSupervisionOptions` is the complement of. One declaration
|
|
212
|
+
* therefore serves both ends — the resolve step cannot produce a set of figures the
|
|
213
|
+
* supervisor does not require, and `buildAndFork` cannot forward a set missing one.
|
|
214
|
+
* It stays FLAT despite the `extends`, and deliberately: `MaterialisationWiring`
|
|
215
|
+
* reads those fields flat, so a nested `supervision` sub-object would ripple into
|
|
216
|
+
* the construction gate and its pure suite for no gain.
|
|
217
|
+
*
|
|
218
|
+
* PACKAGE-INTERNAL and deliberately not re-exported: it is the seam between the two
|
|
219
|
+
* runner entry points, not a shape a caller ever writes. Nothing on it mentions the
|
|
220
|
+
* read model's `E` or its `R`, which is what lets one monomorphic record be shared
|
|
221
|
+
* by a single wiring and by a LIST of them — see `runProjections.ts` for why a type
|
|
222
|
+
* parameterised by one `Materialisation` in this position would not work.
|
|
223
|
+
*/
|
|
224
|
+
export interface ResolvedProjection extends ResolvedSupervisionTuning {
|
|
225
|
+
/** The view store this materialisation writes into, bound to its key. */
|
|
226
|
+
readonly view: KeyedProjectionStore;
|
|
227
|
+
/**
|
|
228
|
+
* The key the commits will use, read OFF the bound view rather than beside it:
|
|
229
|
+
* the read model cannot name a key its store is not bound to, so annotations,
|
|
230
|
+
* defect messages and failure payloads all report the key that actually runs.
|
|
231
|
+
*/
|
|
232
|
+
readonly key: CheckpointKey;
|
|
233
|
+
/** The VIEW's half of R2, passed straight through from the bound store. */
|
|
234
|
+
readonly viewDurability: Durability;
|
|
235
|
+
readonly batchSize: BatchSize;
|
|
236
|
+
readonly batchWindow: Duration.DurationInput;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* RESOLVE: apply every default and read both call-independent facts off the bound
|
|
240
|
+
* view, so the gate can judge exactly the figures the pipeline will run.
|
|
241
|
+
*
|
|
242
|
+
* A PURE function — no `Effect`, no context, no clock — which is what lets BOTH
|
|
243
|
+
* runner entry points share one resolution site. That is the whole reason it exists
|
|
244
|
+
* as a function rather than as a paragraph of `runProjection`'s body: the gate is
|
|
245
|
+
* only as good as the argument it is handed, and two resolution sites are free to
|
|
246
|
+
* drift into approving a figure the pipeline does not use. One site, and the figure
|
|
247
|
+
* that was judged cannot differ from the figure that runs, for one wiring and for N
|
|
248
|
+
* of them alike.
|
|
249
|
+
*
|
|
250
|
+
* The five `??` defaults are resolved HERE and ONCE. `batchSize` and `batchWindow`
|
|
251
|
+
* go into the pipeline, the three restart durations into the supervision options,
|
|
252
|
+
* where `superviseOnProgress` requires all three for exactly that reason.
|
|
253
|
+
*
|
|
254
|
+
* `maxNoProgressRestarts` is deliberately absent, as it is from the gate: it is
|
|
255
|
+
* BRANDED, so its boundary was the caller's own `.make(...)`, nothing here has to
|
|
256
|
+
* resolve it, and its default stays where its wall-clock arithmetic is documented.
|
|
257
|
+
*
|
|
258
|
+
* It takes the BOUND view rather than the unbound port because `key` and
|
|
259
|
+
* `viewDurability` are its two reads and both are on the bound façade. The UNBOUND
|
|
260
|
+
* store is still the only thing that can answer "are these two entries the same
|
|
261
|
+
* store?" — `forKey` deliberately does not expose what it closed over — so the gate
|
|
262
|
+
* takes that identity as a field of its own, from whichever caller holds one.
|
|
263
|
+
*/
|
|
264
|
+
export declare const resolveProjection: (view: KeyedProjectionStore, options?: ProjectionRunnerOptions) => ResolvedProjection;
|
|
265
|
+
declare const PipelineDied_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
266
|
+
readonly _tag: "PipelineDied";
|
|
267
|
+
} & Readonly<A>;
|
|
268
|
+
/**
|
|
269
|
+
* A defect surfaced from the drain, converted into a value the supervisor can act
|
|
270
|
+
* on.
|
|
271
|
+
*
|
|
272
|
+
* **Why the conversion exists.** `DcbEventStore.subscribe` is `E = never` by
|
|
273
|
+
* contract (ADR-0002: infrastructure faults are defects, not channel values), so a
|
|
274
|
+
* store whose live tail fails beyond its own retry budget DIES rather than failing.
|
|
275
|
+
* Converting that death into a typed error at the runner's boundary is what makes
|
|
276
|
+
* it actionable: a defect can only be caught, whereas a value can be counted,
|
|
277
|
+
* logged, matched on, and fed to a supervisor that decides between backoff and
|
|
278
|
+
* give-up.
|
|
279
|
+
*
|
|
280
|
+
* **Why the boundary is DRAIN-WIDE**, which is what the name reports. The
|
|
281
|
+
* conversion sits outside the whole `runDrain`, so what arrives is a defect from
|
|
282
|
+
* any stage of it: the subscription's own death, the codec's decode, the read
|
|
283
|
+
* model's `apply`, or a `ProjectionStore` implementation that dies where the port
|
|
284
|
+
* says it should fail. They all end the run identically, and the progress-keyed
|
|
285
|
+
* breaker is the right arbiter for all of them, since it restarts while the
|
|
286
|
+
* checkpoint moves and gives up with a logged `ProjectionStalled` when it does
|
|
287
|
+
* not. Narrowing the conversion to the subscription stage would instead let an
|
|
288
|
+
* `apply` defect escape `Effect.retry` — which sees failures, never defects — and
|
|
289
|
+
* kill the daemon fibre outright: no restart, no `ProjectionStalled`, no logged
|
|
290
|
+
* give-up, and since `runProjection` is infallible, no route to an operator at
|
|
291
|
+
* all. The boundary must equally not WIDEN to `catchAllCause`; the comment at the
|
|
292
|
+
* conversion site sets out why.
|
|
293
|
+
*
|
|
294
|
+
* `defect` is `unknown` because it is somebody else's defect and the runner must
|
|
295
|
+
* not pretend to know its shape.
|
|
296
|
+
*/
|
|
297
|
+
export declare class PipelineDied extends PipelineDied_base<{
|
|
298
|
+
readonly key: CheckpointKey;
|
|
299
|
+
readonly defect: unknown;
|
|
300
|
+
}> {
|
|
301
|
+
/**
|
|
302
|
+
* Why this class fills `message` at all: so the fault renders ITSELF.
|
|
303
|
+
*
|
|
304
|
+
* `Data.TaggedError` sets `name` to the tag and leaves `message` empty, so an
|
|
305
|
+
* unfilled tagged error stringifies to its bare tag — "the pipeline died", with
|
|
306
|
+
* no hint of what killed it, and `PipelineDied: ECONNRESET` is not the same log
|
|
307
|
+
* line. Filled, `Error.prototype.toString` yields `name: message`, so
|
|
308
|
+
* `String(fault)`, `Cause.pretty` (which reads `message` off anything
|
|
309
|
+
* `instanceof Error`) and every log line built from either report the field that
|
|
310
|
+
* says WHY — and no table of tag-to-label outside the class has to be kept in
|
|
311
|
+
* step with the fields inside it.
|
|
312
|
+
*
|
|
313
|
+
* `String(this.defect)` rather than anything cleverer, for exactly the reason
|
|
314
|
+
* `defect` is `unknown` above: plucking a `.message`, sniffing a `_tag` or
|
|
315
|
+
* `JSON.stringify`-ing it would each be the runner pretending to know the shape
|
|
316
|
+
* of somebody else's defect, and the last of them THROWS on a `bigint`.
|
|
317
|
+
*
|
|
318
|
+
* A GETTER rather than a `message` field, which keeps `defect` the single
|
|
319
|
+
* declaration of the fact. Why a prototype accessor is safe here, how far filling
|
|
320
|
+
* the field reaches and the structured `toJSON` shape it deliberately leaves
|
|
321
|
+
* untouched are set out once for all four of these getters on
|
|
322
|
+
* `ProjectionStoreError` in `ProjectionStore.ts`.
|
|
323
|
+
*/
|
|
324
|
+
get message(): string;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* A running projection: the bound view store it maintains, the key it maintains it
|
|
328
|
+
* under, and the daemon fibre doing the maintaining.
|
|
329
|
+
*
|
|
330
|
+
* The fibre is exposed rather than hidden so a caller can `Fiber.poll` it (is this
|
|
331
|
+
* projection still up?), `Fiber.await` it, or `Fiber.interrupt` it early — the
|
|
332
|
+
* last being the documented answer to "give up immediately", which
|
|
333
|
+
* `MaxNoProgressRestarts` deliberately does not offer as a supervision policy. It
|
|
334
|
+
* is NOT the teardown mechanism: the fibre is forked into the enclosing `Scope`,
|
|
335
|
+
* so closing that scope interrupts it deterministically and waits for it, which is
|
|
336
|
+
* what makes a shutdown graceful — the in-flight commit either completes or was
|
|
337
|
+
* never started, and either way the checkpoint matches the view.
|
|
338
|
+
*
|
|
339
|
+
* A full `RuntimeFiber` rather than something `Fiber.await`-shaped (an
|
|
340
|
+
* `Effect<never, ProjectionStalled>`, which would leave awaiting the terminal
|
|
341
|
+
* failure as the only thing a caller could do), for two reasons that arrived
|
|
342
|
+
* together. Awaiting is no longer how a stall is noticed — `onStalled` is, and it
|
|
343
|
+
* works under `projectionLayer` too, where there IS no handle because the daemon
|
|
344
|
+
* is discarded on purpose — so narrowing this type would be narrowing towards the
|
|
345
|
+
* weaker of the two routes. And the two capabilities it would remove, polling and
|
|
346
|
+
* interrupting, are the ones with no equivalent on an awaitable: "is it still
|
|
347
|
+
* running?" cannot be asked of an effect that only completes when it is not, and
|
|
348
|
+
* the early stop is guidance this repo gives elsewhere in prose.
|
|
349
|
+
*
|
|
350
|
+
* ## Why the BOUND STORE is carried, and why here rather than beside the handle
|
|
351
|
+
*
|
|
352
|
+
* Because it is what tells N runners of ONE read model apart wherever their keys do
|
|
353
|
+
* not — which is the ordinary case, a distinct `PartitionId` being the escape hatch
|
|
354
|
+
* for two materialisations COHABITING one store rather than the normal shape. Under
|
|
355
|
+
* one `ProjectionId`, wherever no entry named a partition, the N `CheckpointKey`s are
|
|
356
|
+
* EQUAL — which is the intended shape, a key naming a cursor WITHIN a store, so equal
|
|
357
|
+
* keys across two stores are one read model materialised twice rather than a clash —
|
|
358
|
+
* and a handle carrying only that key therefore cannot name which cursor it advances.
|
|
359
|
+
* `runProjections` did the `forKey` binding for the caller, so without this field
|
|
360
|
+
* every observer of a multi-materialisation call had to re-derive a binding the
|
|
361
|
+
* library had already made, from a key and a store it had to pair up again by hand.
|
|
362
|
+
*
|
|
363
|
+
* Carried ON the runner rather than returned beside it (`{ runner, store }` per
|
|
364
|
+
* entry) because of where the two entry points get their store from. `runProjection`
|
|
365
|
+
* is HANDED the bound store by its caller, so a pair would hand back what that caller
|
|
366
|
+
* already holds; `runProjections` is the one place the caller does not hold it. One
|
|
367
|
+
* field on the handle covers both, and it keeps "one materialisation, one key, one
|
|
368
|
+
* runner" readable off a single value.
|
|
369
|
+
*
|
|
370
|
+
* What it does NOT do is pair a runner back with the entry that asked for it. An
|
|
371
|
+
* entry hands `runProjections` an UNBOUND port and `forKey` deliberately does not
|
|
372
|
+
* expose what it closed over, so this field can be OBSERVED but not matched against a
|
|
373
|
+
* store the caller still holds; the returned ENTRY ORDER is what states that pairing,
|
|
374
|
+
* and `runProjections` says so where it fixes the order.
|
|
375
|
+
*/
|
|
376
|
+
export interface ProjectionRunner {
|
|
377
|
+
/**
|
|
378
|
+
* The key this projection advances — `store.key`, so it names the cursor the
|
|
379
|
+
* commits actually use rather than one stated beside it.
|
|
380
|
+
*
|
|
381
|
+
* Kept as a field of its own although the store carries it, because it is what
|
|
382
|
+
* almost every reader wants (log lines, a `ProjectionStalled` payload, an
|
|
383
|
+
* operator's "which projection?") and reaching it through the store would be a
|
|
384
|
+
* hop for nothing.
|
|
385
|
+
*/
|
|
386
|
+
readonly key: CheckpointKey;
|
|
387
|
+
/**
|
|
388
|
+
* The view store this daemon commits through, bound to `key` — the runner's own
|
|
389
|
+
* cursor, and the discriminator among N materialisations of one read model.
|
|
390
|
+
*
|
|
391
|
+
* Exposed for OBSERVING: `readCheckpoint` (how far has THIS materialisation got?),
|
|
392
|
+
* `durability` and `key`. `commit` and `resetCheckpoint` are on it because
|
|
393
|
+
* `KeyedProjectionStore` is one interface, and neither should be called while this
|
|
394
|
+
* runner is up — the daemon is this cursor's SINGLE WRITER (ADR-0007), so a write
|
|
395
|
+
* from anywhere else races the guarded advance it owns and costs the loser a
|
|
396
|
+
* restart. A rebuild takes the runner down first (close the enclosing `Scope`) and
|
|
397
|
+
* resets the cursor after.
|
|
398
|
+
*/
|
|
399
|
+
readonly store: KeyedProjectionStore;
|
|
400
|
+
/** The daemon fibre. Interrupted when the enclosing `Scope` closes. */
|
|
401
|
+
readonly fibre: Fiber.RuntimeFiber<void, ProjectionStalled>;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* The decode stage a build step is handed: `decodeSlices`' return type, named.
|
|
405
|
+
*
|
|
406
|
+
* It stays GENERIC in the input stream's own error and requirement, exactly as
|
|
407
|
+
* `decodeSlices` is, so one stage built for a call can be applied to every
|
|
408
|
+
* subscription in it. Naming the type is what makes passing the stage as an
|
|
409
|
+
* ARGUMENT possible without instantiating it at the first call site — which is what
|
|
410
|
+
* `runProjections` needs, since it builds one stage and hands it to N pipelines.
|
|
411
|
+
*
|
|
412
|
+
* `RSlices` is the slice record's OWN requirement, which rides out in the decoded
|
|
413
|
+
* stream's `R`. It is the REQUIREMENT rather than the record it came from because
|
|
414
|
+
* `RequirementOf<T>` is a conditional type: nothing could recover `T` from a stage
|
|
415
|
+
* handed over as a value, so a record parameter would be uninferable here.
|
|
416
|
+
*
|
|
417
|
+
* TWO references to this alias are LOAD-BEARING: `PreparedProjection.decode`, the
|
|
418
|
+
* SOURCE, where the stage is handed over, and `buildAndFork`'s own `decode`
|
|
419
|
+
* parameter, the TARGET, where it is taken. With source and target both written
|
|
420
|
+
* through the alias, TypeScript infers straight from its type ARGUMENT
|
|
421
|
+
* and never has to unify two generic signatures' return unions, which it cannot do
|
|
422
|
+
* here (`SR` and `RSlices` are both naked variables in one union, so it gives up and
|
|
423
|
+
* infers `unknown`). Widen EITHER and the failure is loud in both entry points at
|
|
424
|
+
* once — `RSlices` collapses to `unknown` and neither declared requirement is
|
|
425
|
+
* satisfiable — which is measured rather than asserted.
|
|
426
|
+
*
|
|
427
|
+
* `prepareProjection`'s own local is annotated through the alias too, and that one is
|
|
428
|
+
* DOCUMENTARY rather than load-bearing — it restates `decodeSlices`' declared return
|
|
429
|
+
* type, so dropping it compiles clean. Worth saying, because the field and the local
|
|
430
|
+
* look like one precaution written twice and only one of them is holding anything up.
|
|
431
|
+
*/
|
|
432
|
+
export type DecodeStage<RSlices> = <SE, SR>(events: Stream.Stream<SequencedEvent, SE, SR>) => Stream.Stream<DecodedEvent, SE | CodecError, SR | RSlices | Serializer>;
|
|
433
|
+
/**
|
|
434
|
+
* PREPARE's whole output: the ONE composed query every subscription in a call
|
|
435
|
+
* subscribes with, and the ONE decode stage every pipeline in it runs.
|
|
436
|
+
*
|
|
437
|
+
* Both are pure derivations of a single `slices` value and both are handed straight
|
|
438
|
+
* to `buildAndFork`, which holds no slice record of its own — so there is no second
|
|
439
|
+
* record either could have been derived differently from. PACKAGE-INTERNAL, like
|
|
440
|
+
* `ResolvedProjection` beside it: it is a seam between the phases, not a shape a
|
|
441
|
+
* caller ever writes.
|
|
442
|
+
*/
|
|
443
|
+
export interface PreparedProjection<T extends Record<string, SliceProjection>> {
|
|
444
|
+
/** `composeProjections`' merged query, shared by the call's N subscriptions. */
|
|
445
|
+
readonly query: Query;
|
|
446
|
+
/** `decodeSlices`' stage, shared by the call's N pipelines. */
|
|
447
|
+
readonly decode: DecodeStage<RequirementOf<T>>;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* PREPARE: the whole middle of a projection call — the log's durability, the merged
|
|
451
|
+
* query, the construction gate's verdict and the decode stage — between the
|
|
452
|
+
* per-entry RESOLVE above and the per-entry BUILD below.
|
|
453
|
+
*
|
|
454
|
+
* ## Why it is a phase of its own
|
|
455
|
+
*
|
|
456
|
+
* Everything in it is a function of the CALL rather than of any one materialisation,
|
|
457
|
+
* and both entry points ran these same five steps in this same order before it
|
|
458
|
+
* existed. `runProjection` is the N = 1 case: it hands over a singleton entry list
|
|
459
|
+
* and its own preamble and gets back the pair `runProjections` gets back for N.
|
|
460
|
+
*
|
|
461
|
+
* ## What the ONE body is FOR: the gate is consulted before the codec
|
|
462
|
+
*
|
|
463
|
+
* This is worth more than the duplication it removes. `decodeSlices` refuses a slice
|
|
464
|
+
* record carrying two DISTINCT `Schema`s under one event type, and refuses it by
|
|
465
|
+
* THROWING — which inside this `Effect.gen` is a defect, exactly as the gate's
|
|
466
|
+
* verdict is. A record wrong in BOTH ways therefore has two sentences available and
|
|
467
|
+
* nothing but the ORDER of two statements decides which one its author reads. The
|
|
468
|
+
* gate's is the right one: it is the read side's own rule about the wiring in front
|
|
469
|
+
* of that author, where the codec's is about a merge the write path shares and
|
|
470
|
+
* `decode.ts` owns.
|
|
471
|
+
*
|
|
472
|
+
* That order is now a property of ONE body — the gate call above, the `decodeSlices`
|
|
473
|
+
* call below — for both entry points at once. It used to be a claim two function
|
|
474
|
+
* bodies each made in prose, free to drift, and pinned for only one of them. It is
|
|
475
|
+
* pinned for both now: `test/runProjections.test.ts`'s "the GATE is consulted before
|
|
476
|
+
* the codec" case and `test/runner.construction.test.ts`'s sibling each drive a
|
|
477
|
+
* record breaking both rules and assert which sentence comes back. Neither RULE is
|
|
478
|
+
* under test in either — `packages/codec`'s decode suite and
|
|
479
|
+
* `projectionWiringFault.test.ts` own those.
|
|
480
|
+
*
|
|
481
|
+
* ## What the caller keeps
|
|
482
|
+
*
|
|
483
|
+
* The PREAMBLE, and only the preamble: `runProjection` names the projection and its
|
|
484
|
+
* partition, `runProjections` the projection alone, and this function joins whichever
|
|
485
|
+
* it was to the gate's sentence about the RULE with one `': '`. That is the division
|
|
486
|
+
* `projectionWiringFault`'s doc fixes — the gate knows the rule, the entry point
|
|
487
|
+
* knows whose wiring it is — and moving the single `Effect.die` here changes only
|
|
488
|
+
* WHERE the two halves meet, never which half writes which. It is built eagerly, one
|
|
489
|
+
* interpolation per construction, rather than as a thunk: a call that is about to
|
|
490
|
+
* subscribe to an event log does not need that deferred, and a thunk reads worse at
|
|
491
|
+
* both call sites.
|
|
492
|
+
*
|
|
493
|
+
* ## Why both derivations happen HERE
|
|
494
|
+
*
|
|
495
|
+
* The runner needs only the merged QUERY from the composition — the fold is the read
|
|
496
|
+
* model's own `apply` — but it must be the SAME merge a fold would use, so it comes
|
|
497
|
+
* from `core`'s `composeProjections` rather than a local query union that could drift
|
|
498
|
+
* from it. It is also the gate's input, and the gate can only judge it at
|
|
499
|
+
* construction because the union is a pure function of the slices.
|
|
500
|
+
*
|
|
501
|
+
* Both derivations run ONCE per call rather than once per entry or once per restart,
|
|
502
|
+
* so N subscriptions share a single `Query` object and N pipelines a single merged
|
|
503
|
+
* `type -> Schema` table. Sharing the decode stage is safe because the `Serializer`
|
|
504
|
+
* is read from context INSIDE it, per stream, so one stage does not freeze one
|
|
505
|
+
* serialiser across entries. `DecodeStage`'s own doc says which references to that
|
|
506
|
+
* alias hold the inference up, and which do not.
|
|
507
|
+
*
|
|
508
|
+
* The cast erases each slice's own state and event types down to `AnyProjection`. It
|
|
509
|
+
* is sound because `composeProjections` only ever folds a slice through its OWN
|
|
510
|
+
* `evolve`, never across two, so the per-slice pairing the erasure hides is the one
|
|
511
|
+
* thing it cannot violate — and `T`'s precise shape is recovered on the way out, in
|
|
512
|
+
* `CompositeState<T>`. It is unavoidable rather than merely convenient: a slice
|
|
513
|
+
* record is keyed by a caller's literal union, and no signature in `core` is generic
|
|
514
|
+
* over that union AND over each member's state, so the variance has to be discharged
|
|
515
|
+
* somewhere. Once, now, rather than at each entry point.
|
|
516
|
+
*
|
|
517
|
+
* ## Why `EventLogDurability` is read from CONTEXT here
|
|
518
|
+
*
|
|
519
|
+
* Because it is R2's log half, and one log is ONE fact —
|
|
520
|
+
* `EventLogDurability.ts` argues why it is a service declared beside the store layer
|
|
521
|
+
* rather than a field per read model. Reading it once for the CALL is what that
|
|
522
|
+
* argument already wanted, and it is deliberately not part of `resolveProjection`,
|
|
523
|
+
* which is per ENTRY and pure. It is this function's only requirement, and through it
|
|
524
|
+
* the reason both entry points declare one.
|
|
525
|
+
*/
|
|
526
|
+
export declare const prepareProjection: <T extends Record<string, SliceProjection>>(slices: T, materialisations: ReadonlyArray<MaterialisationWiring>, preamble: string) => Effect.Effect<PreparedProjection<T>, never, EventLogDurability>;
|
|
527
|
+
/**
|
|
528
|
+
* BUILD and FORK: one resolved wiring plus the three shared derivations in, one
|
|
529
|
+
* supervised daemon out.
|
|
530
|
+
*
|
|
531
|
+
* This is everything the two runner entry points have in common from the gate's
|
|
532
|
+
* verdict onwards — the subscription, the decode, the micro-batching, the guarded
|
|
533
|
+
* commit, the supervisor and the `forkScoped`. It is package-internal and takes no
|
|
534
|
+
* `ReadModel`, so `runProjections` reaches it directly rather than by re-entering
|
|
535
|
+
* `runProjection` per entry, which is what lets one call resolve, judge and derive
|
|
536
|
+
* ONCE and still run N identical pipelines. `read-postgres`'s
|
|
537
|
+
* `test/courseRosterGraduation.test.ts` rests on the two callers running literally
|
|
538
|
+
* the same pipeline, so this function staying the only build step is load-bearing.
|
|
539
|
+
*
|
|
540
|
+
* It requires no `EventLogDurability`. That service is read by `prepareProjection`
|
|
541
|
+
* above — the one place it is read at all — for the gate, and has no part in what
|
|
542
|
+
* runs; the two public entry points DECLARE it only because they run that phase.
|
|
543
|
+
*
|
|
544
|
+
* `query` and `decode` arrive as ARGUMENTS rather than being derived here from a
|
|
545
|
+
* slice record, which is a structural gain rather than a cost: the build step holds
|
|
546
|
+
* no slice record at all, so there is no second record it could derive a different
|
|
547
|
+
* query or a different decode table from. It is the same move `decodeSlices` itself
|
|
548
|
+
* made when it collapsed a two-step protocol into one call.
|
|
549
|
+
*/
|
|
550
|
+
export declare const buildAndFork: <RSlices, E, R>(resolved: ResolvedProjection, build: {
|
|
551
|
+
readonly query: Query;
|
|
552
|
+
readonly decode: DecodeStage<RSlices>;
|
|
553
|
+
readonly apply: (batch: Arr.NonEmptyReadonlyArray<DecodedEvent>) => Effect.Effect<void, E, R>;
|
|
554
|
+
readonly options: ProjectionRunnerOptions | undefined;
|
|
555
|
+
}) => Effect.Effect<ProjectionRunner, never, Scope.Scope | DcbEventStore | Serializer | RSlices | R>;
|
|
556
|
+
export {};
|
|
557
|
+
//# sourceMappingURL=ProjectionRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectionRunner.d.ts","sourceRoot":"","sources":["../../src/ProjectionRunner.ts"],"names":[],"mappings":"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"}
|