effect-dynamodb 1.27.0 → 1.29.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/dist/Batch.d.ts.map +1 -1
- package/dist/Batch.js +3 -2
- package/dist/Batch.js.map +1 -1
- package/dist/Entity.d.ts +24 -1
- package/dist/Entity.d.ts.map +1 -1
- package/dist/Entity.js +33 -17
- package/dist/Entity.js.map +1 -1
- package/dist/EventStore.d.ts +66 -5
- package/dist/EventStore.d.ts.map +1 -1
- package/dist/EventStore.js +100 -2
- package/dist/EventStore.js.map +1 -1
- package/dist/Transaction.d.ts.map +1 -1
- package/dist/Transaction.js +5 -2
- package/dist/Transaction.js.map +1 -1
- package/dist/change-feed/ChangeFeed.d.ts +203 -0
- package/dist/change-feed/ChangeFeed.d.ts.map +1 -0
- package/dist/change-feed/ChangeFeed.js +498 -0
- package/dist/change-feed/ChangeFeed.js.map +1 -0
- package/dist/change-feed/CheckpointStore.d.ts +113 -0
- package/dist/change-feed/CheckpointStore.d.ts.map +1 -0
- package/dist/change-feed/CheckpointStore.js +247 -0
- package/dist/change-feed/CheckpointStore.js.map +1 -0
- package/dist/change-feed/DynamoStreamsClient.d.ts +71 -0
- package/dist/change-feed/DynamoStreamsClient.d.ts.map +1 -0
- package/dist/change-feed/DynamoStreamsClient.js +92 -0
- package/dist/change-feed/DynamoStreamsClient.js.map +1 -0
- package/dist/change-feed/Errors.d.ts +84 -0
- package/dist/change-feed/Errors.d.ts.map +1 -0
- package/dist/change-feed/Errors.js +40 -0
- package/dist/change-feed/Errors.js.map +1 -0
- package/dist/change-feed/index.d.ts +36 -0
- package/dist/change-feed/index.d.ts.map +1 -0
- package/dist/change-feed/index.js +36 -0
- package/dist/change-feed/index.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/EntityOps.d.ts +7 -2
- package/dist/internal/EntityOps.d.ts.map +1 -1
- package/dist/internal/EntityOps.js.map +1 -1
- package/dist/internal/EventProjection.d.ts +782 -0
- package/dist/internal/EventProjection.d.ts.map +1 -0
- package/dist/internal/EventProjection.js +608 -0
- package/dist/internal/EventProjection.js.map +1 -0
- package/dist/internal/MultiProjection.d.ts +255 -0
- package/dist/internal/MultiProjection.d.ts.map +1 -0
- package/dist/internal/MultiProjection.js +377 -0
- package/dist/internal/MultiProjection.js.map +1 -0
- package/dist/internal/ProjectionEngine.d.ts +253 -0
- package/dist/internal/ProjectionEngine.d.ts.map +1 -0
- package/dist/internal/ProjectionEngine.js +837 -0
- package/dist/internal/ProjectionEngine.js.map +1 -0
- package/dist/internal/TransactWriteOps.d.ts.map +1 -1
- package/dist/internal/TransactWriteOps.js +12 -3
- package/dist/internal/TransactWriteOps.js.map +1 -1
- package/dist/internal/TransactableOps.d.ts +44 -1
- package/dist/internal/TransactableOps.d.ts.map +1 -1
- package/dist/internal/TransactableOps.js +52 -2
- package/dist/internal/TransactableOps.js.map +1 -1
- package/package.json +14 -3
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A polled change feed: an Effect `Stream` over a DynamoDB stream's records,
|
|
3
|
+
* for consumers outside Lambda and EventBridge Pipes (#156). See
|
|
4
|
+
* `docs/designs/change-feed.md`.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { Cause, Clock, Deferred, Duration, Effect, Option, Queue, Random, Result, Schedule, Semaphore, Stream, } from "effect";
|
|
9
|
+
import { processBatch, } from "../internal/EventProjection.js";
|
|
10
|
+
import { CheckpointStore } from "./CheckpointStore.js";
|
|
11
|
+
import { DynamoStreamsClient } from "./DynamoStreamsClient.js";
|
|
12
|
+
import { ChangeFeedLeaseLost, ChangeFeedTrimmed, } from "./Errors.js";
|
|
13
|
+
const isTransient = (error) => error._tag === "ThrottlingError" || error._tag === "InternalServerError";
|
|
14
|
+
/**
|
|
15
|
+
* A change feed over `options.streamArn`: a `Stream` of {@link ChangeFeedBatch}es.
|
|
16
|
+
*
|
|
17
|
+
* - **Shards** are found with `DescribeStream` (paginated), at start and every
|
|
18
|
+
* `describeInterval`; a drained shard's children are looked up with
|
|
19
|
+
* `ShardFilter` (`CHILD_SHARDS`), falling back to a full describe where the
|
|
20
|
+
* filter is unsupported (DynamoDB Local) or finds nothing yet.
|
|
21
|
+
* - **A parent shard is read to its end before its children**, so one item's
|
|
22
|
+
* records stay in order across a split. A closed shard is drained, its last
|
|
23
|
+
* batch acknowledged, checkpointed as finished, and dropped.
|
|
24
|
+
* - **Shards are read concurrently**, each in order with one batch in flight:
|
|
25
|
+
* a shard reads again only once its batch is acknowledged, so a slow
|
|
26
|
+
* consumer slows polling.
|
|
27
|
+
* `maxConcurrentReads` bounds the reads in flight across shards.
|
|
28
|
+
* - **Checkpoints** move only when a batch is acknowledged — at least once.
|
|
29
|
+
* A shard resumes after its checkpoint (`AFTER_SEQUENCE_NUMBER`). An expired
|
|
30
|
+
* iterator is re-acquired from the shard's position; a position past the
|
|
31
|
+
* stream's retention fails with `ChangeFeedTrimmed`.
|
|
32
|
+
* - **Throttling and transient errors** retry with jittered backoff. An idle
|
|
33
|
+
* shard polls every `pollInterval`.
|
|
34
|
+
* - **The lease** keeps a second process from consuming the same feed.
|
|
35
|
+
*
|
|
36
|
+
* The stream ends when the stream is disabled and every shard is drained;
|
|
37
|
+
* otherwise it runs until interrupted.
|
|
38
|
+
*
|
|
39
|
+
* Throws `[EDD-9083]` for options it can't honour: `lease.renewEvery` of half
|
|
40
|
+
* `lease.duration` or more, a `batchSize` outside 1–1000, a
|
|
41
|
+
* `maxConcurrentReads` that is not a positive integer.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const feed = changeFeed({ streamArn, startingPosition: "TRIM_HORIZON" })
|
|
46
|
+
* yield* feed.pipe(
|
|
47
|
+
* Stream.mapEffect((batch) => handle(batch.records).pipe(Effect.andThen(batch.commit()))),
|
|
48
|
+
* Stream.runDrain,
|
|
49
|
+
* )
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export const changeFeed = (options) => {
|
|
53
|
+
validate(options);
|
|
54
|
+
return Stream.callback((queue) => run(options, queue).pipe(Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : Queue.failCause(queue, cause))));
|
|
55
|
+
};
|
|
56
|
+
/** The lease's `duration` and `renewEvery`, defaults applied. */
|
|
57
|
+
const leaseTiming = (lease) => {
|
|
58
|
+
const duration = Duration.fromInputUnsafe(lease.duration ?? "30 seconds");
|
|
59
|
+
const renewEvery = Duration.fromInputUnsafe(lease.renewEvery ?? Duration.millis(Math.max(1, Math.floor(Duration.toMillis(duration) / 3))));
|
|
60
|
+
return { duration, renewEvery };
|
|
61
|
+
};
|
|
62
|
+
/** Refuse options the feed can't honour — `[EDD-9083]`. */
|
|
63
|
+
const validate = (options) => {
|
|
64
|
+
const refuse = (problem) => {
|
|
65
|
+
throw new Error(`[EDD-9083] changeFeed("${options.streamArn}"): ${problem}`);
|
|
66
|
+
};
|
|
67
|
+
if (options.lease !== false && options.lease !== undefined) {
|
|
68
|
+
const { duration, renewEvery } = leaseTiming(options.lease);
|
|
69
|
+
if (!(Duration.toMillis(renewEvery) > 0))
|
|
70
|
+
refuse("lease.renewEvery must be positive.");
|
|
71
|
+
if (Duration.toMillis(renewEvery) * 2 >= Duration.toMillis(duration)) {
|
|
72
|
+
refuse(`lease.renewEvery (${Duration.toMillis(renewEvery)} ms) must be less than half of ` +
|
|
73
|
+
`lease.duration (${Duration.toMillis(duration)} ms), to leave time to retry a ` +
|
|
74
|
+
"renewal the store fails to write before the lease lapses.");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const reads = options.maxConcurrentReads;
|
|
78
|
+
if (reads !== undefined && !(Number.isInteger(reads) && reads >= 1)) {
|
|
79
|
+
refuse(`maxConcurrentReads must be a positive integer, got ${reads}.`);
|
|
80
|
+
}
|
|
81
|
+
const size = options.batchSize;
|
|
82
|
+
if (size !== undefined && !(Number.isInteger(size) && size >= 1 && size <= 1000)) {
|
|
83
|
+
refuse(`batchSize must be an integer from 1 to 1000, got ${size}.`);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const run = (options, queue) => Effect.gen(function* () {
|
|
87
|
+
const client = yield* DynamoStreamsClient;
|
|
88
|
+
const store = yield* CheckpointStore;
|
|
89
|
+
const scope = yield* Effect.scope;
|
|
90
|
+
const { streamArn } = options;
|
|
91
|
+
const feed = { streamArn, consumer: options.consumer ?? "default" };
|
|
92
|
+
const pollInterval = Duration.fromInputUnsafe(options.pollInterval ?? "1 second");
|
|
93
|
+
const describeInterval = Duration.fromInputUnsafe(options.describeInterval ?? "30 seconds");
|
|
94
|
+
const batchSize = options.batchSize ?? 100;
|
|
95
|
+
const initialBackoff = Duration.fromInputUnsafe(options.backoff?.initial ?? "100 millis");
|
|
96
|
+
const maxBackoff = Duration.fromInputUnsafe(options.backoff?.max ?? "10 seconds");
|
|
97
|
+
const backoff = Schedule.jittered(Schedule.min([Schedule.exponential(initialBackoff, 2), Schedule.spaced(maxBackoff)]));
|
|
98
|
+
/** Retry throttling and transient errors without limit. */
|
|
99
|
+
const transient = (effect) => Effect.retry(effect, { schedule: backoff, while: isTransient });
|
|
100
|
+
/** Fail the stream with a forked fiber's failure. */
|
|
101
|
+
const failStream = (effect) => effect.pipe(Effect.asVoid, Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : Queue.failCause(queue, cause)));
|
|
102
|
+
/** Bounds the shard reads in flight; held for one call, not across a backoff. */
|
|
103
|
+
const reads = yield* Semaphore.make(options.maxConcurrentReads ?? 16);
|
|
104
|
+
const read = (effect) => transient(Semaphore.withPermit(reads, effect));
|
|
105
|
+
/** A jittered delay growing per consecutive failure, capped at `backoff.max`. */
|
|
106
|
+
const retryDelay = (failures) => Effect.map(Random.nextBetween(0.8, 1.2), (jitter) => Duration.millis(Math.min(Duration.toMillis(maxBackoff), Duration.toMillis(initialBackoff) * 2 ** failures) * jitter));
|
|
107
|
+
// -- Lease -------------------------------------------------------------
|
|
108
|
+
/** Set once the lease is lost: acknowledgements then fail, writing nothing. */
|
|
109
|
+
let leaseLost;
|
|
110
|
+
if (options.lease !== false) {
|
|
111
|
+
const lease = options.lease ?? {};
|
|
112
|
+
const { duration, renewEvery } = leaseTiming(lease);
|
|
113
|
+
const owner = lease.owner ?? globalThis.crypto.randomUUID();
|
|
114
|
+
const acquire = store.acquireLease(feed, owner, duration);
|
|
115
|
+
yield* lease.onHeld === "wait"
|
|
116
|
+
? Effect.retry(acquire, {
|
|
117
|
+
schedule: Schedule.spaced(renewEvery),
|
|
118
|
+
while: (error) => error._tag === "ChangeFeedLeaseHeld",
|
|
119
|
+
})
|
|
120
|
+
: acquire;
|
|
121
|
+
yield* Effect.addFinalizer(() => Effect.ignore(store.releaseLease(feed, owner)));
|
|
122
|
+
let renewedAt = yield* Clock.currentTimeMillis;
|
|
123
|
+
const lost = (error) => {
|
|
124
|
+
leaseLost = new ChangeFeedLeaseLost({ streamArn, consumer: feed.consumer, owner });
|
|
125
|
+
return Effect.fail(error);
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Renew the lease. A store failure is retried until the lease is about
|
|
129
|
+
* to lapse — `renewEvery` before it expires — and a lease taken over is
|
|
130
|
+
* not retried; either way the lease counts as lost.
|
|
131
|
+
*/
|
|
132
|
+
const renew = Effect.gen(function* () {
|
|
133
|
+
const deadline = renewedAt + Duration.toMillis(duration) - Duration.toMillis(renewEvery);
|
|
134
|
+
for (let attempt = 0;; attempt++) {
|
|
135
|
+
const at = yield* Clock.currentTimeMillis;
|
|
136
|
+
const result = yield* Effect.result(store.renewLease(feed, owner, duration));
|
|
137
|
+
if (Result.isSuccess(result)) {
|
|
138
|
+
renewedAt = at;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const now = yield* Clock.currentTimeMillis;
|
|
142
|
+
if (result.failure._tag !== "CheckpointStoreError" || now >= deadline) {
|
|
143
|
+
return yield* lost(result.failure);
|
|
144
|
+
}
|
|
145
|
+
const delay = yield* retryDelay(attempt);
|
|
146
|
+
yield* Effect.sleep(Duration.millis(Math.min(Duration.toMillis(delay), deadline - now)));
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
yield* Effect.forkIn(failStream(Effect.forever(Effect.sleep(renewEvery).pipe(Effect.andThen(renew)))), scope);
|
|
150
|
+
}
|
|
151
|
+
// -- Shards ------------------------------------------------------------
|
|
152
|
+
const checkpoints = yield* store.load(feed);
|
|
153
|
+
const fresh = checkpoints.size === 0;
|
|
154
|
+
/** Every shard described, by id — updated by each describe (a shard closes). */
|
|
155
|
+
const known = new Map();
|
|
156
|
+
const started = new Set();
|
|
157
|
+
const finished = new Set();
|
|
158
|
+
for (const [shardId, checkpoint] of checkpoints) {
|
|
159
|
+
if (checkpoint._tag === "Finished")
|
|
160
|
+
finished.add(shardId);
|
|
161
|
+
}
|
|
162
|
+
/** At a fresh `LATEST` start, the shards open at that moment. */
|
|
163
|
+
const latest = new Set();
|
|
164
|
+
let status;
|
|
165
|
+
let shardFilter = true;
|
|
166
|
+
/** Shards missing from a describe that a probe found still there, all closed parents. */
|
|
167
|
+
const probedClosed = new Set();
|
|
168
|
+
/**
|
|
169
|
+
* Asks the describer for a full describe soon: drained shards that find no
|
|
170
|
+
* children share one describe instead of each running their own.
|
|
171
|
+
*/
|
|
172
|
+
const wake = yield* Queue.dropping(1);
|
|
173
|
+
const absorb = (shards) => {
|
|
174
|
+
for (const shard of shards)
|
|
175
|
+
if (shard.ShardId !== undefined)
|
|
176
|
+
known.set(shard.ShardId, shard);
|
|
177
|
+
};
|
|
178
|
+
/** `DescribeStream`, transient errors retried (it raises no iterator errors). */
|
|
179
|
+
const describe = (input) => transient(client.describeStream(input)).pipe(Effect.catchTags({
|
|
180
|
+
ShardIteratorExpired: (e) => Effect.die(e),
|
|
181
|
+
StreamDataTrimmed: (e) => Effect.die(e),
|
|
182
|
+
}));
|
|
183
|
+
const describeAll = Effect.gen(function* () {
|
|
184
|
+
const shards = [];
|
|
185
|
+
let ExclusiveStartShardId;
|
|
186
|
+
do {
|
|
187
|
+
const page = yield* describe({
|
|
188
|
+
StreamArn: streamArn,
|
|
189
|
+
...(ExclusiveStartShardId === undefined ? {} : { ExclusiveStartShardId }),
|
|
190
|
+
});
|
|
191
|
+
shards.push(...(page.StreamDescription?.Shards ?? []));
|
|
192
|
+
status = page.StreamDescription?.StreamStatus ?? status;
|
|
193
|
+
ExclusiveStartShardId = page.StreamDescription?.LastEvaluatedShardId;
|
|
194
|
+
} while (ExclusiveStartShardId !== undefined);
|
|
195
|
+
absorb(shards);
|
|
196
|
+
// Forget finished shards that have left the stream (24 h after closing),
|
|
197
|
+
// so a long-running feed does not accumulate them.
|
|
198
|
+
const listed = new Set(shards.flatMap((shard) => (shard.ShardId === undefined ? [] : [shard.ShardId])));
|
|
199
|
+
for (const shardId of [...known.keys()]) {
|
|
200
|
+
if (!listed.has(shardId) && finished.has(shardId)) {
|
|
201
|
+
known.delete(shardId);
|
|
202
|
+
started.delete(shardId);
|
|
203
|
+
finished.delete(shardId);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return listed;
|
|
207
|
+
});
|
|
208
|
+
/**
|
|
209
|
+
* The children of a drained shard — with `ShardFilter`, or, where the
|
|
210
|
+
* filter is unsupported or finds none yet, the describer's next full
|
|
211
|
+
* describe, which it runs soon (shared by every shard drained meanwhile).
|
|
212
|
+
*/
|
|
213
|
+
const discoverChildren = (parentId) => Effect.gen(function* () {
|
|
214
|
+
if (shardFilter) {
|
|
215
|
+
const filtered = yield* describe({
|
|
216
|
+
StreamArn: streamArn,
|
|
217
|
+
ShardFilter: { Type: "CHILD_SHARDS", ShardId: parentId },
|
|
218
|
+
}).pipe(Effect.map(Option.some), Effect.catchTag("DynamoValidationError", () => {
|
|
219
|
+
shardFilter = false;
|
|
220
|
+
return Effect.succeed(Option.none());
|
|
221
|
+
}));
|
|
222
|
+
if (Option.isSome(filtered)) {
|
|
223
|
+
const description = filtered.value.StreamDescription;
|
|
224
|
+
status = description?.StreamStatus ?? status;
|
|
225
|
+
const children = (description?.Shards ?? []).filter((s) => s.ParentShardId === parentId);
|
|
226
|
+
absorb(children);
|
|
227
|
+
if (children.length > 0)
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
Queue.offerUnsafe(wake, undefined);
|
|
232
|
+
});
|
|
233
|
+
const isOpen = (shardId) => !probedClosed.has(shardId) &&
|
|
234
|
+
known.get(shardId)?.SequenceNumberRange?.EndingSequenceNumber === undefined;
|
|
235
|
+
const startPosition = (shardId) => {
|
|
236
|
+
const checkpoint = checkpoints.get(shardId);
|
|
237
|
+
if (checkpoint?._tag === "Sequence") {
|
|
238
|
+
return { type: "AFTER_SEQUENCE_NUMBER", sequenceNumber: checkpoint.sequenceNumber };
|
|
239
|
+
}
|
|
240
|
+
return { type: latest.has(shardId) ? "LATEST" : "TRIM_HORIZON" };
|
|
241
|
+
};
|
|
242
|
+
/** Hand a batch to the consumer and wait for its acknowledgement. */
|
|
243
|
+
const deliver = (shardId, records) => Effect.gen(function* () {
|
|
244
|
+
const ack = yield* Deferred.make();
|
|
245
|
+
const sequences = records.map((record) => record.dynamodb?.SequenceNumber ?? "");
|
|
246
|
+
const first = sequences[0];
|
|
247
|
+
const last = sequences[sequences.length - 1];
|
|
248
|
+
// Acknowledgements run one at a time; the first whose checkpoint is
|
|
249
|
+
// written settles the batch, and a failed write leaves it unsettled, so
|
|
250
|
+
// a retry writes again.
|
|
251
|
+
const lock = yield* Semaphore.make(1);
|
|
252
|
+
let settled = false;
|
|
253
|
+
const settle = (checkpoint, result) => Semaphore.withPermit(lock, Effect.suspend(() => {
|
|
254
|
+
if (settled)
|
|
255
|
+
return Effect.void;
|
|
256
|
+
if (leaseLost !== undefined)
|
|
257
|
+
return Effect.fail(leaseLost);
|
|
258
|
+
return (checkpoint === undefined
|
|
259
|
+
? Effect.void
|
|
260
|
+
: store.commit(feed, shardId, { _tag: "Sequence", sequenceNumber: checkpoint })).pipe(Effect.andThen(Effect.suspend(() => {
|
|
261
|
+
settled = true;
|
|
262
|
+
return Deferred.succeed(ack, result);
|
|
263
|
+
})), Effect.asVoid);
|
|
264
|
+
}));
|
|
265
|
+
const commit = () => settle(last, { _tag: "Continue" });
|
|
266
|
+
const complete = (response) => Effect.suspend(() => {
|
|
267
|
+
if (response.batchItemFailures.length === 0)
|
|
268
|
+
return commit();
|
|
269
|
+
const failed = new Set(response.batchItemFailures.map((f) => f.itemIdentifier));
|
|
270
|
+
const inBatch = new Set(sequences);
|
|
271
|
+
// An identifier naming no record fails the whole batch, as Lambda does.
|
|
272
|
+
const at = [...failed].some((id) => !inBatch.has(id))
|
|
273
|
+
? 0
|
|
274
|
+
: sequences.findIndex((sequence) => failed.has(sequence));
|
|
275
|
+
const acknowledged = at === 0 ? undefined : sequences[at - 1];
|
|
276
|
+
return settle(acknowledged, { _tag: "Retry", from: sequences[at], acknowledged });
|
|
277
|
+
});
|
|
278
|
+
yield* Queue.offer(queue, {
|
|
279
|
+
streamArn,
|
|
280
|
+
shardId,
|
|
281
|
+
records,
|
|
282
|
+
firstSequenceNumber: first,
|
|
283
|
+
lastSequenceNumber: last,
|
|
284
|
+
commit,
|
|
285
|
+
complete,
|
|
286
|
+
});
|
|
287
|
+
return yield* Deferred.await(ack);
|
|
288
|
+
});
|
|
289
|
+
/** Read one shard to its end (it closed and every record was acknowledged). */
|
|
290
|
+
const readShard = (shardId, start) => Effect.gen(function* () {
|
|
291
|
+
let position = start;
|
|
292
|
+
let acknowledged = start.type === "AFTER_SEQUENCE_NUMBER" ? start.sequenceNumber : undefined;
|
|
293
|
+
let iterator;
|
|
294
|
+
let failures = 0;
|
|
295
|
+
let misses = 0;
|
|
296
|
+
const trimmed = (cause) => new ChangeFeedTrimmed({ streamArn, shardId, sequenceNumber: acknowledged, cause });
|
|
297
|
+
while (true) {
|
|
298
|
+
if (iterator === undefined) {
|
|
299
|
+
const acquired = yield* read(client.getShardIterator({
|
|
300
|
+
StreamArn: streamArn,
|
|
301
|
+
ShardId: shardId,
|
|
302
|
+
ShardIteratorType: position.type,
|
|
303
|
+
...("sequenceNumber" in position
|
|
304
|
+
? { SequenceNumber: position.sequenceNumber }
|
|
305
|
+
: {}),
|
|
306
|
+
})).pipe(Effect.catchTag("StreamDataTrimmed", (e) => Effect.fail(trimmed(e.cause))), Effect.catchTag("ShardIteratorExpired", (e) => Effect.die(e)));
|
|
307
|
+
iterator = acquired.ShardIterator;
|
|
308
|
+
if (iterator === undefined) {
|
|
309
|
+
// No iterator. A closed shard has nothing left to read; for one
|
|
310
|
+
// the stream still lists as open, refresh the list and retry.
|
|
311
|
+
const listed = yield* describeAll;
|
|
312
|
+
if (!listed.has(shardId)) {
|
|
313
|
+
return yield* trimmed(new Error(`Shard ${shardId} is no longer in the stream`));
|
|
314
|
+
}
|
|
315
|
+
if (!isOpen(shardId))
|
|
316
|
+
return;
|
|
317
|
+
yield* Effect.sleep(yield* retryDelay(misses++));
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
misses = 0;
|
|
321
|
+
}
|
|
322
|
+
const page = yield* read(client.getRecords({ ShardIterator: iterator, Limit: batchSize })).pipe(Effect.map(Option.some), Effect.catchTag("ShardIteratorExpired", () => Effect.succeed(Option.none())), Effect.catchTag("StreamDataTrimmed", (e) => Effect.fail(trimmed(e.cause))));
|
|
323
|
+
if (Option.isNone(page)) {
|
|
324
|
+
// Re-acquire from the shard's position.
|
|
325
|
+
iterator = undefined;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const records = page.value.Records ?? [];
|
|
329
|
+
if (records.length > 0) {
|
|
330
|
+
const ack = yield* deliver(shardId, records);
|
|
331
|
+
if (ack._tag === "Retry") {
|
|
332
|
+
if (ack.acknowledged !== undefined)
|
|
333
|
+
acknowledged = ack.acknowledged;
|
|
334
|
+
position = { type: "AT_SEQUENCE_NUMBER", sequenceNumber: ack.from };
|
|
335
|
+
iterator = undefined;
|
|
336
|
+
yield* Effect.sleep(yield* retryDelay(failures++));
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
failures = 0;
|
|
340
|
+
acknowledged = records[records.length - 1].dynamodb?.SequenceNumber ?? acknowledged;
|
|
341
|
+
if (acknowledged !== undefined) {
|
|
342
|
+
position = { type: "AFTER_SEQUENCE_NUMBER", sequenceNumber: acknowledged };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const next = page.value.NextShardIterator;
|
|
346
|
+
// No next iterator: the shard is closed and read to its end.
|
|
347
|
+
if (next === undefined)
|
|
348
|
+
return;
|
|
349
|
+
iterator = next;
|
|
350
|
+
if (records.length === 0 && isOpen(shardId))
|
|
351
|
+
yield* Effect.sleep(pollInterval);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
/** End the stream once the stream is disabled and every shard is drained. */
|
|
355
|
+
const maybeEnd = Effect.suspend(() => status === "DISABLED" &&
|
|
356
|
+
[...known.keys()].every((shardId) => finished.has(shardId)) &&
|
|
357
|
+
[...started].every((shardId) => finished.has(shardId))
|
|
358
|
+
? Effect.asVoid(Queue.end(queue))
|
|
359
|
+
: Effect.void);
|
|
360
|
+
/** Start every shard whose parent is drained (or gone). */
|
|
361
|
+
const schedule = Effect.suspend(() => {
|
|
362
|
+
const ready = [];
|
|
363
|
+
for (const [shardId, shard] of known) {
|
|
364
|
+
if (started.has(shardId) || finished.has(shardId))
|
|
365
|
+
continue;
|
|
366
|
+
const parent = shard.ParentShardId;
|
|
367
|
+
if (parent !== undefined && known.has(parent) && !finished.has(parent))
|
|
368
|
+
continue;
|
|
369
|
+
started.add(shardId);
|
|
370
|
+
ready.push(shardId);
|
|
371
|
+
}
|
|
372
|
+
return Effect.forEach(ready, (shardId) => Effect.forkIn(failStream(shardLifecycle(shardId)), scope), { discard: true });
|
|
373
|
+
});
|
|
374
|
+
const shardLifecycle = (shardId) => Effect.gen(function* () {
|
|
375
|
+
yield* readShard(shardId, startPosition(shardId));
|
|
376
|
+
yield* store.commit(feed, shardId, { _tag: "Finished" });
|
|
377
|
+
finished.add(shardId);
|
|
378
|
+
yield* discoverChildren(shardId);
|
|
379
|
+
yield* schedule;
|
|
380
|
+
yield* maybeEnd;
|
|
381
|
+
});
|
|
382
|
+
/**
|
|
383
|
+
* Whether a shard missing from a describe is still in the stream — its
|
|
384
|
+
* trim horizon still yields an iterator. Gone: not found, or trimmed.
|
|
385
|
+
*/
|
|
386
|
+
const exists = (shardId) => read(client.getShardIterator({
|
|
387
|
+
StreamArn: streamArn,
|
|
388
|
+
ShardId: shardId,
|
|
389
|
+
ShardIteratorType: "TRIM_HORIZON",
|
|
390
|
+
})).pipe(Effect.as(true), Effect.catchTags({
|
|
391
|
+
ResourceNotFoundError: () => Effect.succeed(false),
|
|
392
|
+
StreamDataTrimmed: () => Effect.succeed(false),
|
|
393
|
+
ShardIteratorExpired: (e) => Effect.die(e),
|
|
394
|
+
}));
|
|
395
|
+
let listed = yield* describeAll;
|
|
396
|
+
/**
|
|
397
|
+
* Shards this consumer may still owe records from that the describe did
|
|
398
|
+
* not list: shards with a `Sequence` checkpoint, and the unfinished parents
|
|
399
|
+
* of listed shards it has not started.
|
|
400
|
+
*/
|
|
401
|
+
const unlisted = () => {
|
|
402
|
+
const ids = new Map();
|
|
403
|
+
for (const [shardId, checkpoint] of checkpoints) {
|
|
404
|
+
if (checkpoint._tag === "Sequence" && !listed.has(shardId))
|
|
405
|
+
ids.set(shardId, "checkpoint");
|
|
406
|
+
}
|
|
407
|
+
for (const [shardId, shard] of known) {
|
|
408
|
+
const parent = shard.ParentShardId;
|
|
409
|
+
if (parent !== undefined &&
|
|
410
|
+
!checkpoints.has(shardId) &&
|
|
411
|
+
!listed.has(parent) &&
|
|
412
|
+
!finished.has(parent) &&
|
|
413
|
+
!ids.has(parent)) {
|
|
414
|
+
ids.set(parent, "parent");
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return ids;
|
|
418
|
+
};
|
|
419
|
+
let missing = unlisted();
|
|
420
|
+
// A describe may omit a shard that is still there: describe once more,
|
|
421
|
+
// then probe what is still missing before treating it as gone.
|
|
422
|
+
if (missing.size > 0) {
|
|
423
|
+
listed = yield* describeAll;
|
|
424
|
+
missing = unlisted();
|
|
425
|
+
}
|
|
426
|
+
for (const [shardId, kind] of missing) {
|
|
427
|
+
if (yield* exists(shardId)) {
|
|
428
|
+
// Still there: read it like any other shard, before its children.
|
|
429
|
+
known.set(shardId, { ShardId: shardId });
|
|
430
|
+
if (kind === "parent")
|
|
431
|
+
probedClosed.add(shardId);
|
|
432
|
+
}
|
|
433
|
+
else if (fresh) {
|
|
434
|
+
// Gone before this consumer started: nothing of it is owed. Recorded,
|
|
435
|
+
// so a restart can tell it from a lost one.
|
|
436
|
+
yield* store.commit(feed, shardId, { _tag: "Finished" });
|
|
437
|
+
finished.add(shardId);
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
// Gone while this consumer still owed records from it (downtime past
|
|
441
|
+
// the 24-hour retention): its unread records are lost.
|
|
442
|
+
const checkpoint = checkpoints.get(shardId);
|
|
443
|
+
return yield* new ChangeFeedTrimmed({
|
|
444
|
+
streamArn,
|
|
445
|
+
shardId,
|
|
446
|
+
sequenceNumber: checkpoint?._tag === "Sequence" ? checkpoint.sequenceNumber : undefined,
|
|
447
|
+
cause: new Error(`Shard ${shardId} is no longer in the stream, and was not read to its end`),
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (fresh && options.startingPosition === "LATEST") {
|
|
452
|
+
for (const [shardId] of known) {
|
|
453
|
+
if (isOpen(shardId)) {
|
|
454
|
+
latest.add(shardId);
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
yield* store.commit(feed, shardId, { _tag: "Finished" });
|
|
458
|
+
finished.add(shardId);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
yield* schedule;
|
|
463
|
+
yield* maybeEnd;
|
|
464
|
+
// The describer: every `describeInterval`, or soon after a drained shard
|
|
465
|
+
// found no children — at most one describe per `pollInterval` for those.
|
|
466
|
+
yield* Effect.forkIn(failStream(Effect.forever(Effect.gen(function* () {
|
|
467
|
+
yield* Effect.raceFirst(Effect.sleep(describeInterval), Queue.take(wake));
|
|
468
|
+
yield* Queue.clear(wake);
|
|
469
|
+
yield* describeAll;
|
|
470
|
+
yield* schedule;
|
|
471
|
+
yield* maybeEnd;
|
|
472
|
+
yield* Effect.sleep(pollInterval);
|
|
473
|
+
}))), scope);
|
|
474
|
+
});
|
|
475
|
+
/**
|
|
476
|
+
* Run a change feed into projections: each batch goes through
|
|
477
|
+
* `EventStore.processBatch(batch.records, { projections, source: "lambda" })`,
|
|
478
|
+
* then `batch.complete(result.response)` — the checkpoint moves past the
|
|
479
|
+
* batch, or to the record before its earliest failed record, which the shard
|
|
480
|
+
* reads again. Batches of different shards are processed concurrently.
|
|
481
|
+
*
|
|
482
|
+
* Runs until the feed ends (its stream disabled and drained) or fails.
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```ts
|
|
486
|
+
* yield* runChangeFeed(changeFeed({ streamArn }), {
|
|
487
|
+
* projections: { summaries: OrderSummaryProjection },
|
|
488
|
+
* })
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
export const runChangeFeed = (feed, options) => {
|
|
492
|
+
const { onBatch, ...processOptions } = options;
|
|
493
|
+
return feed.pipe(Stream.mapEffect((batch) => processBatch(batch.records, {
|
|
494
|
+
...processOptions,
|
|
495
|
+
source: "lambda",
|
|
496
|
+
}).pipe(Effect.tap((result) => (onBatch === undefined ? Effect.void : onBatch(batch, result))), Effect.flatMap((result) => batch.complete(result.response))), { concurrency: "unbounded", unordered: true }), Stream.runDrain);
|
|
497
|
+
};
|
|
498
|
+
//# sourceMappingURL=ChangeFeed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChangeFeed.js","sourceRoot":"","sources":["../../src/change-feed/ChangeFeed.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CheckpointStore — where a change feed keeps its per-shard checkpoints and
|
|
3
|
+
* its lease. Two implementations: in memory, and a DynamoDB table.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import type { CreateTableCommandInput } from "@aws-sdk/client-dynamodb";
|
|
8
|
+
import { Context, Duration, Effect, Layer } from "effect";
|
|
9
|
+
import { DynamoClient } from "../DynamoClient.js";
|
|
10
|
+
import { ChangeFeedLeaseHeld, ChangeFeedLeaseLost, CheckpointStoreError } from "./Errors.js";
|
|
11
|
+
/**
|
|
12
|
+
* One consumer of one stream: the unit a checkpoint and a lease belong to.
|
|
13
|
+
* `consumer` names the application, so several applications can consume one
|
|
14
|
+
* stream with one checkpoint table.
|
|
15
|
+
*/
|
|
16
|
+
export interface FeedId {
|
|
17
|
+
readonly streamArn: string;
|
|
18
|
+
readonly consumer: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A shard's checkpoint: the last sequence number whose record was
|
|
22
|
+
* acknowledged, or `Finished` once the shard closed and every record was
|
|
23
|
+
* acknowledged (or, at a fresh `LATEST` start, when it was closed already).
|
|
24
|
+
*/
|
|
25
|
+
export type ShardCheckpoint = {
|
|
26
|
+
readonly _tag: "Sequence";
|
|
27
|
+
readonly sequenceNumber: string;
|
|
28
|
+
} | {
|
|
29
|
+
readonly _tag: "Finished";
|
|
30
|
+
};
|
|
31
|
+
/** The operations a change feed needs from its checkpoint store. */
|
|
32
|
+
export interface CheckpointStoreService {
|
|
33
|
+
/** Every shard checkpoint of the feed, by shard id. */
|
|
34
|
+
readonly load: (feed: FeedId) => Effect.Effect<ReadonlyMap<string, ShardCheckpoint>, CheckpointStoreError>;
|
|
35
|
+
/** Record a shard's checkpoint. */
|
|
36
|
+
readonly commit: (feed: FeedId, shardId: string, checkpoint: ShardCheckpoint) => Effect.Effect<void, CheckpointStoreError>;
|
|
37
|
+
/**
|
|
38
|
+
* Take the feed's lease for `duration` — when there is none, it expired, or
|
|
39
|
+
* `owner` holds it already.
|
|
40
|
+
*/
|
|
41
|
+
readonly acquireLease: (feed: FeedId, owner: string, duration: Duration.Duration) => Effect.Effect<void, ChangeFeedLeaseHeld | CheckpointStoreError>;
|
|
42
|
+
/** Extend `owner`'s lease by `duration` from now; fails when another owner holds it. */
|
|
43
|
+
readonly renewLease: (feed: FeedId, owner: string, duration: Duration.Duration) => Effect.Effect<void, ChangeFeedLeaseLost | CheckpointStoreError>;
|
|
44
|
+
/** Give up `owner`'s lease (nothing when another owner holds it). */
|
|
45
|
+
readonly releaseLease: (feed: FeedId, owner: string) => Effect.Effect<void, CheckpointStoreError>;
|
|
46
|
+
}
|
|
47
|
+
/** A checkpoint store held in memory — for tests and single-process feeds that may start over. */
|
|
48
|
+
export declare const makeMemory: () => CheckpointStoreService;
|
|
49
|
+
/** Options of {@link makeDynamoDB}. */
|
|
50
|
+
export interface DynamoDBCheckpointStoreOptions {
|
|
51
|
+
/** The checkpoint table — see {@link tableDefinition} for its key schema. */
|
|
52
|
+
readonly tableName: string;
|
|
53
|
+
/**
|
|
54
|
+
* How long a `Finished` checkpoint is kept (its `ttl` attribute, honoured
|
|
55
|
+
* when TTL is enabled on the table). A closed shard leaves the stream 24
|
|
56
|
+
* hours after it closes. Default: 2 days; at least {@link MIN_FINISHED_TTL}
|
|
57
|
+
* (28 hours), `[EDD-9084]` otherwise.
|
|
58
|
+
*/
|
|
59
|
+
readonly finishedTtl?: Duration.Input | undefined;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The checkpoint table's `CreateTable` input: `pk` (S, HASH) + `sk` (S, RANGE),
|
|
63
|
+
* on-demand billing. A shard checkpoint is `{ pk: "<consumer>#<streamArn>",
|
|
64
|
+
* sk: "shard#<shardId>", sequenceNumber | finished, updatedAt, ttl? }`; the
|
|
65
|
+
* lease is `{ pk, sk: "lease", owner, expiresAt }`. Enable TTL on `ttl` to
|
|
66
|
+
* expire `Finished` checkpoints.
|
|
67
|
+
*/
|
|
68
|
+
export declare const tableDefinition: (tableName: string) => CreateTableCommandInput & {
|
|
69
|
+
readonly TableName: string;
|
|
70
|
+
};
|
|
71
|
+
/** A checkpoint store on a DynamoDB table, through `DynamoClient`. */
|
|
72
|
+
/**
|
|
73
|
+
* The shortest `finishedTtl` accepted: 28 hours. A `Finished` checkpoint must
|
|
74
|
+
* outlive every shard that depends on it being there — the shard itself, listed
|
|
75
|
+
* up to 24 hours after it closes, and the children of a parent already gone at
|
|
76
|
+
* a fresh start, which can stay listed for a shard's lifetime (about 4 hours)
|
|
77
|
+
* plus those 24 hours. A checkpoint expired earlier makes a restart report
|
|
78
|
+
* `ChangeFeedTrimmed` for records that were never lost.
|
|
79
|
+
*/
|
|
80
|
+
export declare const MIN_FINISHED_TTL: Duration.Duration;
|
|
81
|
+
export declare const makeDynamoDB: (options: DynamoDBCheckpointStoreOptions) => Effect.Effect<CheckpointStoreService, never, DynamoClient>;
|
|
82
|
+
declare const CheckpointStore_base: Context.ServiceClass<CheckpointStore, "@effect-dynamodb/CheckpointStore", CheckpointStoreService>;
|
|
83
|
+
/**
|
|
84
|
+
* Effect `Context.Service` for the change feed's checkpoint store.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* import { CheckpointStore } from "effect-dynamodb/change-feed"
|
|
89
|
+
*
|
|
90
|
+
* // In memory (tests, or a feed that may start over)
|
|
91
|
+
* const Memory = CheckpointStore.layerMemory
|
|
92
|
+
* // In a DynamoDB table (needs DynamoClient)
|
|
93
|
+
* const Durable = CheckpointStore.layerDynamoDB({ tableName: "change-feed-checkpoints" })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare class CheckpointStore extends CheckpointStore_base {
|
|
97
|
+
/** A fresh in-memory store per layer build; its lease is process-local. */
|
|
98
|
+
static readonly layerMemory: Layer.Layer<CheckpointStore>;
|
|
99
|
+
/** The shortest `finishedTtl` accepted — see {@link MIN_FINISHED_TTL}. */
|
|
100
|
+
static readonly minFinishedTtl: Duration.Duration;
|
|
101
|
+
/** A store on a DynamoDB table — see {@link tableDefinition}. */
|
|
102
|
+
static readonly layerDynamoDB: (options: DynamoDBCheckpointStoreOptions) => Layer.Layer<CheckpointStore, never, DynamoClient>;
|
|
103
|
+
/** {@link tableDefinition}: the checkpoint table's `CreateTable` input. */
|
|
104
|
+
static readonly tableDefinition: (tableName: string) => CreateTableCommandInput & {
|
|
105
|
+
readonly TableName: string;
|
|
106
|
+
};
|
|
107
|
+
/** {@link makeMemory}: an in-memory store, as a value. */
|
|
108
|
+
static readonly makeMemory: () => CheckpointStoreService;
|
|
109
|
+
/** {@link makeDynamoDB}: a DynamoDB-table store, as a value. */
|
|
110
|
+
static readonly makeDynamoDB: (options: DynamoDBCheckpointStoreOptions) => Effect.Effect<CheckpointStoreService, never, DynamoClient>;
|
|
111
|
+
}
|
|
112
|
+
export {};
|
|
113
|
+
//# sourceMappingURL=CheckpointStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckpointStore.d.ts","sourceRoot":"","sources":["../../src/change-feed/CheckpointStore.ts"],"names":[],"mappings":"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"}
|