@kensio/yulin 1.21.8 → 1.21.10
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/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.d.ts +1 -1
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +6 -3
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-names.d.ts +30 -0
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-names.js +91 -0
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.d.ts +7 -12
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +12 -92
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.d.ts +2 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.js +5 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-refusals.js +0 -10
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.d.ts +2 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.js +2 -0
- package/dist/service/lambda/command/event-source-mapping/sim-lambda-event-source-mapping-commands.d.ts +2 -0
- package/dist/service/lambda/destination/sim-lambda-destination-targets.d.ts +2 -1
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.d.ts +0 -4
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.js +11 -16
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.d.ts +1 -6
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.js +9 -27
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.d.ts +19 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.js +27 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-event-source-function.d.ts +1 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-event-source-function.js +3 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-age.d.ts +13 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-age.js +27 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-info.d.ts +15 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-info.js +26 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-outcome.d.ts +1 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-outcome.js +7 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-processing.d.ts +17 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-processing.js +12 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-bisect.d.ts +53 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-bisect.js +79 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-cursor.d.ts +15 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-cursor.js +28 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-expiry.d.ts +19 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-expiry.js +23 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-context.d.ts +3 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-context.js +19 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-destination.d.ts +15 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-destination.js +38 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-record.d.ts +41 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-record.js +17 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.d.ts +23 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.js +42 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.d.ts +21 -38
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.js +45 -63
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-retry.d.ts +4 -39
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-retry.js +12 -64
- package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.d.ts +10 -3
- package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.js +12 -3
- package/dist/service/lambda/event-source/sim-lambda-event-source-retry-limits.d.ts +8 -7
- package/dist/service/lambda/event-source/sim-lambda-event-source-retry-limits.js +6 -3
- package/dist/service/lambda/event-source/sim-lambda-stream-destination-config.d.ts +7 -0
- package/dist/service/lambda/event-source/sim-lambda-stream-destination-config.js +38 -0
- package/dist/service/lambda/event-source/sim-lambda-stream-retry-limits.d.ts +15 -7
- package/dist/service/lambda/event-source/sim-lambda-stream-retry-limits.js +15 -7
- package/dist/service/lambda/event-source/stream/kinesis/sim-kinesis-event-source-streams.js +1 -0
- package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-reader.js +1 -0
- package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-shard.d.ts +1 -0
- package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-shard.js +7 -0
- package/dist/service/lambda/event-source/stream/sim-lambda-event-source-streams.d.ts +1 -0
- package/dist/service/lambda/index.d.ts +1 -0
- package/dist/service/lambda/sim-lambda-commands.js +1 -0
- package/docs/services/lambda/README.md +111 -11
- package/package.json +1 -1
|
@@ -1,27 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
1
|
+
import { type SimLambdaStreamProgressProperties } from "./sim-lambda-stream-progress-state.js";
|
|
2
|
+
import type { SimLambdaStreamRecordTime } from "./sim-lambda-stream-record-times.js";
|
|
3
|
+
import type { SimLambdaFunction } from "../../function/sim-lambda-function.js";
|
|
3
4
|
import type { SimLambdaEventSourceStreamPosition, SimLambdaEventSourceStreamProgressBatch } from "../stream/sim-lambda-event-source-streams.js";
|
|
4
5
|
import type { SimLambdaStreamBatchOutcome } from "./sim-lambda-stream-batch-outcome.js";
|
|
5
|
-
|
|
6
|
-
readonly mapping: SimLambdaEventSourceMapping;
|
|
7
|
-
readonly background: BackgroundScheduler;
|
|
8
|
-
readonly poll: BackgroundTask;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* How far along its stream one mapping has got, and what it does next.
|
|
12
|
-
*
|
|
13
|
-
* The two belong together because they are the same decision. A batch the
|
|
14
|
-
* function took moves the checkpoint and the mapping reads on; a batch it threw
|
|
15
|
-
* on leaves the checkpoint where it is and the mapping tries the same records
|
|
16
|
-
* again after a wait; a batch it reported failing partway through moves the
|
|
17
|
-
* checkpoint back to the record it named. Nothing behind a failing batch is
|
|
18
|
-
* read until it is through, which is what it means for a stream mapping to
|
|
19
|
-
* block its shard.
|
|
20
|
-
*/
|
|
6
|
+
/** Apply a stream batch outcome to its checkpoint and retry schedule. */
|
|
21
7
|
export declare class SimLambdaStreamProgress {
|
|
22
|
-
private readonly
|
|
23
|
-
private readonly retry;
|
|
24
|
-
private readonly schedule;
|
|
8
|
+
private readonly state;
|
|
25
9
|
constructor(properties: SimLambdaStreamProgressProperties);
|
|
26
10
|
/**
|
|
27
11
|
* Poll as soon as the simulation gets to it.
|
|
@@ -31,6 +15,11 @@ export declare class SimLambdaStreamProgress {
|
|
|
31
15
|
* Where the next read starts.
|
|
32
16
|
*/
|
|
33
17
|
get position(): SimLambdaEventSourceStreamPosition;
|
|
18
|
+
/**
|
|
19
|
+
* How many records the next read may take, which is the mapping's batch size
|
|
20
|
+
* until a batch is being bisected.
|
|
21
|
+
*/
|
|
22
|
+
batchSizeWithin(batchSize: number): number;
|
|
34
23
|
/**
|
|
35
24
|
* Take a read that came back with nothing.
|
|
36
25
|
*
|
|
@@ -40,9 +29,18 @@ export declare class SimLambdaStreamProgress {
|
|
|
40
29
|
*/
|
|
41
30
|
caughtUp(batch: SimLambdaEventSourceStreamProgressBatch): void;
|
|
42
31
|
/**
|
|
43
|
-
*
|
|
32
|
+
* Drop the records at the front of a batch that are too old to hand over,
|
|
33
|
+
* answering with where the live ones start.
|
|
34
|
+
*
|
|
35
|
+
* Records that aged out are as finished with as records the function took, so
|
|
36
|
+
* a batch being split counts them off its remainder too.
|
|
37
|
+
*/
|
|
38
|
+
before(records: readonly SimLambdaStreamRecordTime[], batch: SimLambdaEventSourceStreamProgressBatch, simFunction: SimLambdaFunction): Promise<number>;
|
|
39
|
+
/**
|
|
40
|
+
* Take what became of a batch: move past it, split it, or wait and try it
|
|
41
|
+
* again.
|
|
44
42
|
*/
|
|
45
|
-
after(outcome: SimLambdaStreamBatchOutcome, batch: SimLambdaEventSourceStreamProgressBatch): void
|
|
43
|
+
after(outcome: SimLambdaStreamBatchOutcome, batch: SimLambdaEventSourceStreamProgressBatch, simFunction: SimLambdaFunction): Promise<void>;
|
|
46
44
|
/**
|
|
47
45
|
* Move past a batch that is finished with, and read on.
|
|
48
46
|
*
|
|
@@ -50,19 +48,4 @@ export declare class SimLambdaStreamProgress {
|
|
|
50
48
|
* given up on.
|
|
51
49
|
*/
|
|
52
50
|
handled(batch: SimLambdaEventSourceStreamProgressBatch): void;
|
|
53
|
-
/**
|
|
54
|
-
* Wait and hand a failed batch over again, or give up on it.
|
|
55
|
-
*
|
|
56
|
-
* Giving up discards the records and carries on with the stream, which is
|
|
57
|
-
* what AWS does when a stream mapping's error handling runs out. Parking the
|
|
58
|
-
* shard instead would be a simulator invention.
|
|
59
|
-
*
|
|
60
|
-
* A batch runs out either by having had its retries or by every record left
|
|
61
|
-
* in it being older than the mapping will carry. Records that aged out of the
|
|
62
|
-
* front of a batch are left behind, and the ones behind them go over again,
|
|
63
|
-
* so a mapping given a record age keeps working through its shard rather than
|
|
64
|
-
* stalling on the oldest record on it.
|
|
65
|
-
*/
|
|
66
|
-
failed(outcome: SimLambdaStreamBatchOutcome, batch: SimLambdaEventSourceStreamProgressBatch): void;
|
|
67
51
|
}
|
|
68
|
-
export {};
|
|
@@ -1,47 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { SimLambdaStreamCheckpoint } from "./sim-lambda-stream-checkpoint.js";
|
|
4
|
-
import { SimLambdaStreamRetry } from "./sim-lambda-stream-retry.js";
|
|
5
|
-
/**
|
|
6
|
-
* How far along its stream one mapping has got, and what it does next.
|
|
7
|
-
*
|
|
8
|
-
* The two belong together because they are the same decision. A batch the
|
|
9
|
-
* function took moves the checkpoint and the mapping reads on; a batch it threw
|
|
10
|
-
* on leaves the checkpoint where it is and the mapping tries the same records
|
|
11
|
-
* again after a wait; a batch it reported failing partway through moves the
|
|
12
|
-
* checkpoint back to the record it named. Nothing behind a failing batch is
|
|
13
|
-
* read until it is through, which is what it means for a stream mapping to
|
|
14
|
-
* block its shard.
|
|
15
|
-
*/
|
|
1
|
+
import { SimLambdaStreamProgressState, } from "./sim-lambda-stream-progress-state.js";
|
|
2
|
+
/** Apply a stream batch outcome to its checkpoint and retry schedule. */
|
|
16
3
|
export class SimLambdaStreamProgress {
|
|
17
|
-
|
|
18
|
-
retry;
|
|
19
|
-
schedule;
|
|
4
|
+
state;
|
|
20
5
|
constructor(properties) {
|
|
21
|
-
|
|
22
|
-
// position, so one that has got this far without one is the simulator
|
|
23
|
-
// having gone wrong rather than a request having been wrong.
|
|
24
|
-
const { start, streamRetryLimits } = properties.mapping;
|
|
25
|
-
assertDefined(start, "stream mapping start position");
|
|
26
|
-
assertDefined(streamRetryLimits, "stream mapping retry limits");
|
|
27
|
-
this.checkpoint = new SimLambdaStreamCheckpoint(start);
|
|
28
|
-
this.retry = new SimLambdaStreamRetry({
|
|
29
|
-
limits: streamRetryLimits,
|
|
30
|
-
clock: properties.background,
|
|
31
|
-
});
|
|
32
|
-
this.schedule = new PollSchedule(properties);
|
|
6
|
+
this.state = new SimLambdaStreamProgressState(properties);
|
|
33
7
|
}
|
|
34
8
|
/**
|
|
35
9
|
* Poll as soon as the simulation gets to it.
|
|
36
10
|
*/
|
|
37
11
|
pollNow() {
|
|
38
|
-
this.
|
|
12
|
+
this.state.cursor.pollNow();
|
|
39
13
|
}
|
|
40
14
|
/**
|
|
41
15
|
* Where the next read starts.
|
|
42
16
|
*/
|
|
43
17
|
get position() {
|
|
44
|
-
return this.
|
|
18
|
+
return this.state.cursor.position;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* How many records the next read may take, which is the mapping's batch size
|
|
22
|
+
* until a batch is being bisected.
|
|
23
|
+
*/
|
|
24
|
+
batchSizeWithin(batchSize) {
|
|
25
|
+
return this.state.bisect.sizeWithin(batchSize);
|
|
45
26
|
}
|
|
46
27
|
/**
|
|
47
28
|
* Take a read that came back with nothing.
|
|
@@ -51,17 +32,44 @@ export class SimLambdaStreamProgress {
|
|
|
51
32
|
* than working out a new one each time.
|
|
52
33
|
*/
|
|
53
34
|
caughtUp(batch) {
|
|
54
|
-
this.
|
|
35
|
+
this.state.cursor.advanceTo(batch.next);
|
|
55
36
|
}
|
|
56
37
|
/**
|
|
57
|
-
*
|
|
38
|
+
* Drop the records at the front of a batch that are too old to hand over,
|
|
39
|
+
* answering with where the live ones start.
|
|
40
|
+
*
|
|
41
|
+
* Records that aged out are as finished with as records the function took, so
|
|
42
|
+
* a batch being split counts them off its remainder too.
|
|
58
43
|
*/
|
|
59
|
-
|
|
44
|
+
async before(records, batch, simFunction) {
|
|
45
|
+
const firstLive = await this.state.expiry.before(records, batch, simFunction);
|
|
46
|
+
this.state.bisect.finished(firstLive);
|
|
47
|
+
return firstLive;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Take what became of a batch: move past it, split it, or wait and try it
|
|
51
|
+
* again.
|
|
52
|
+
*/
|
|
53
|
+
async after(outcome, batch, simFunction) {
|
|
54
|
+
this.state.failures.invoked(outcome);
|
|
60
55
|
if (outcome.isHandled) {
|
|
56
|
+
this.state.bisect.finished(outcome.records.length);
|
|
61
57
|
this.handled(batch);
|
|
62
58
|
return;
|
|
63
59
|
}
|
|
64
|
-
this.
|
|
60
|
+
if (this.state.bisect.split(outcome)) {
|
|
61
|
+
this.state.retry.reset();
|
|
62
|
+
}
|
|
63
|
+
const again = this.state.retry.after(outcome, this.position);
|
|
64
|
+
const notification = this.state.failures.deliver(this.state.retry.discarded, batch, simFunction);
|
|
65
|
+
if (again === undefined) {
|
|
66
|
+
this.state.bisect.finished(outcome.records.length);
|
|
67
|
+
this.handled(batch);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.state.cursor.resume(again);
|
|
71
|
+
}
|
|
72
|
+
await notification;
|
|
65
73
|
}
|
|
66
74
|
/**
|
|
67
75
|
* Move past a batch that is finished with, and read on.
|
|
@@ -70,32 +78,6 @@ export class SimLambdaStreamProgress {
|
|
|
70
78
|
* given up on.
|
|
71
79
|
*/
|
|
72
80
|
handled(batch) {
|
|
73
|
-
this.
|
|
74
|
-
this.checkpoint.advanceTo(batch.next);
|
|
75
|
-
if (!batch.drained) {
|
|
76
|
-
this.schedule.now();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Wait and hand a failed batch over again, or give up on it.
|
|
81
|
-
*
|
|
82
|
-
* Giving up discards the records and carries on with the stream, which is
|
|
83
|
-
* what AWS does when a stream mapping's error handling runs out. Parking the
|
|
84
|
-
* shard instead would be a simulator invention.
|
|
85
|
-
*
|
|
86
|
-
* A batch runs out either by having had its retries or by every record left
|
|
87
|
-
* in it being older than the mapping will carry. Records that aged out of the
|
|
88
|
-
* front of a batch are left behind, and the ones behind them go over again,
|
|
89
|
-
* so a mapping given a record age keeps working through its shard rather than
|
|
90
|
-
* stalling on the oldest record on it.
|
|
91
|
-
*/
|
|
92
|
-
failed(outcome, batch) {
|
|
93
|
-
const again = this.retry.after(outcome, this.checkpoint.position);
|
|
94
|
-
if (again === undefined) {
|
|
95
|
-
this.handled(batch);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
this.checkpoint.advanceTo(again.position);
|
|
99
|
-
this.schedule.afterSeconds(again.afterSeconds);
|
|
81
|
+
this.state.handled(batch);
|
|
100
82
|
}
|
|
101
83
|
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
+
import type { SimLambdaStreamDiscard } from "./sim-lambda-stream-failure-record.js";
|
|
1
2
|
import type { SimClock } from "../../../../util/clock/sim-clock.js";
|
|
2
3
|
import type { SimLambdaStreamRetryLimits } from "../sim-lambda-stream-retry-limits.js";
|
|
3
4
|
import type { SimLambdaEventSourceStreamPosition } from "../stream/sim-lambda-event-source-streams.js";
|
|
4
5
|
import type { SimLambdaStreamBatchOutcome } from "./sim-lambda-stream-batch-outcome.js";
|
|
5
|
-
interface SimLambdaStreamRetryProperties {
|
|
6
|
-
readonly limits: SimLambdaStreamRetryLimits;
|
|
7
|
-
readonly clock: SimClock;
|
|
8
|
-
}
|
|
9
6
|
/**
|
|
10
7
|
* One more delivery of a failed batch: where it starts, and how long the
|
|
11
8
|
* mapping waits first.
|
|
@@ -14,26 +11,12 @@ export interface SimLambdaStreamRetryAttempt {
|
|
|
14
11
|
readonly position: SimLambdaEventSourceStreamPosition;
|
|
15
12
|
readonly afterSeconds: number;
|
|
16
13
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Whether a failed batch is handed over again, and from which record.
|
|
19
|
-
*
|
|
20
|
-
* Both of Lambda's failed-batch limits end here because they end the same
|
|
21
|
-
* thing. A batch stops being delivered when it has had its retries, and a
|
|
22
|
-
* record stops being delivered when it is older than the mapping will carry;
|
|
23
|
-
* whichever comes first, what is left of the batch is discarded and the mapping
|
|
24
|
-
* reads on. Records age out of the front of a batch, because a batch is in
|
|
25
|
-
* stream order, so the answer is one record to start from rather than a list of
|
|
26
|
-
* survivors.
|
|
27
|
-
*
|
|
28
|
-
* Ages are read at the instant the next delivery falls due rather than now,
|
|
29
|
-
* because the wait before it is what ages the records out. A record judged now
|
|
30
|
-
* would be handed to the function and only then found to be too old.
|
|
31
|
-
*/
|
|
14
|
+
/** Tracks the retry quota and checkpoint of one failed stream batch. */
|
|
32
15
|
export declare class SimLambdaStreamRetry {
|
|
33
|
-
|
|
16
|
+
discarded: SimLambdaStreamDiscard | undefined;
|
|
34
17
|
private readonly clock;
|
|
35
18
|
private readonly backoff;
|
|
36
|
-
constructor(
|
|
19
|
+
constructor(limits: SimLambdaStreamRetryLimits, clock: SimClock);
|
|
37
20
|
/**
|
|
38
21
|
* The next delivery of a failed batch, or nothing when the batch is finished
|
|
39
22
|
* with.
|
|
@@ -43,22 +26,4 @@ export declare class SimLambdaStreamRetry {
|
|
|
43
26
|
* Start counting again, which a batch that is finished with does.
|
|
44
27
|
*/
|
|
45
28
|
reset(): void;
|
|
46
|
-
/**
|
|
47
|
-
* Where the next delivery starts, or nothing when every record left in the
|
|
48
|
-
* batch has aged out.
|
|
49
|
-
*/
|
|
50
|
-
private retryPosition;
|
|
51
|
-
/**
|
|
52
|
-
* The first record from `from` on that is still young enough to deliver.
|
|
53
|
-
*/
|
|
54
|
-
private firstLiveIndex;
|
|
55
|
-
/**
|
|
56
|
-
* When the next delivery falls due, which is what a record's age is judged
|
|
57
|
-
* against.
|
|
58
|
-
*
|
|
59
|
-
* Judging it now would hand a record over and only then notice that it was
|
|
60
|
-
* too old to be worth handing over, since the wait is what makes it too old.
|
|
61
|
-
*/
|
|
62
|
-
private deliveryAt;
|
|
63
29
|
}
|
|
64
|
-
export {};
|
|
@@ -1,44 +1,29 @@
|
|
|
1
1
|
import { SimLambdaStreamRetryBackoff } from "./sim-lambda-stream-retry-backoff.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Whether a failed batch is handed over again, and from which record.
|
|
5
|
-
*
|
|
6
|
-
* Both of Lambda's failed-batch limits end here because they end the same
|
|
7
|
-
* thing. A batch stops being delivered when it has had its retries, and a
|
|
8
|
-
* record stops being delivered when it is older than the mapping will carry;
|
|
9
|
-
* whichever comes first, what is left of the batch is discarded and the mapping
|
|
10
|
-
* reads on. Records age out of the front of a batch, because a batch is in
|
|
11
|
-
* stream order, so the answer is one record to start from rather than a list of
|
|
12
|
-
* survivors.
|
|
13
|
-
*
|
|
14
|
-
* Ages are read at the instant the next delivery falls due rather than now,
|
|
15
|
-
* because the wait before it is what ages the records out. A record judged now
|
|
16
|
-
* would be handed to the function and only then found to be too old.
|
|
17
|
-
*/
|
|
2
|
+
/** Tracks the retry quota and checkpoint of one failed stream batch. */
|
|
18
3
|
export class SimLambdaStreamRetry {
|
|
19
|
-
|
|
4
|
+
discarded;
|
|
20
5
|
clock;
|
|
21
6
|
backoff;
|
|
22
|
-
constructor(
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this.backoff = new SimLambdaStreamRetryBackoff(properties.limits.attemptLimit);
|
|
7
|
+
constructor(limits, clock) {
|
|
8
|
+
this.clock = clock;
|
|
9
|
+
this.backoff = new SimLambdaStreamRetryBackoff(limits.attemptLimit);
|
|
26
10
|
}
|
|
27
11
|
/**
|
|
28
12
|
* The next delivery of a failed batch, or nothing when the batch is finished
|
|
29
13
|
* with.
|
|
30
14
|
*/
|
|
31
15
|
after(outcome, readFrom) {
|
|
16
|
+
this.discarded = undefined;
|
|
32
17
|
if (this.backoff.isExhausted) {
|
|
18
|
+
this.discarded = {
|
|
19
|
+
records: outcome.records.slice(outcome.retryIndex),
|
|
20
|
+
condition: "RetryAttemptsExhausted",
|
|
21
|
+
at: this.clock.now(),
|
|
22
|
+
};
|
|
33
23
|
return undefined;
|
|
34
24
|
}
|
|
35
25
|
const afterSeconds = this.backoff.nextSeconds();
|
|
36
|
-
|
|
37
|
-
const position = this.retryPosition(outcome, readFrom, deliveryAt);
|
|
38
|
-
if (position === undefined) {
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
return { position, afterSeconds };
|
|
26
|
+
return { position: outcome.retryPosition(readFrom), afterSeconds };
|
|
42
27
|
}
|
|
43
28
|
/**
|
|
44
29
|
* Start counting again, which a batch that is finished with does.
|
|
@@ -46,41 +31,4 @@ export class SimLambdaStreamRetry {
|
|
|
46
31
|
reset() {
|
|
47
32
|
this.backoff.reset();
|
|
48
33
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Where the next delivery starts, or nothing when every record left in the
|
|
51
|
-
* batch has aged out.
|
|
52
|
-
*/
|
|
53
|
-
retryPosition(outcome, readFrom, deliveryAt) {
|
|
54
|
-
const { records, retryIndex } = outcome;
|
|
55
|
-
const live = this.firstLiveIndex(records, retryIndex, deliveryAt);
|
|
56
|
-
if (live === undefined) {
|
|
57
|
-
return undefined;
|
|
58
|
-
}
|
|
59
|
-
const sequenceNumber = records.at(live)?.sequenceNumber;
|
|
60
|
-
// Nothing aged out of the front, so the batch goes back exactly where the
|
|
61
|
-
// report left it. A record that aged out but cannot be named leaves the
|
|
62
|
-
// batch where it was too, since skipping past a record the mapping cannot
|
|
63
|
-
// name would skip the records after it as well.
|
|
64
|
-
if (live === retryIndex || sequenceNumber === undefined) {
|
|
65
|
-
return outcome.retryPosition(readFrom);
|
|
66
|
-
}
|
|
67
|
-
return { kind: "sequence", sequenceNumber };
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* The first record from `from` on that is still young enough to deliver.
|
|
71
|
-
*/
|
|
72
|
-
firstLiveIndex(records, from, deliveryAt) {
|
|
73
|
-
const index = records.findIndex((record, position) => position >= from && !this.limits.hasAgedOut(record.at, deliveryAt));
|
|
74
|
-
return index === -1 ? undefined : index;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* When the next delivery falls due, which is what a record's age is judged
|
|
78
|
-
* against.
|
|
79
|
-
*
|
|
80
|
-
* Judging it now would hand a record over and only then notice that it was
|
|
81
|
-
* too old to be worth handing over, since the wait is what makes it too old.
|
|
82
|
-
*/
|
|
83
|
-
deliveryAt(afterSeconds) {
|
|
84
|
-
return new Date(this.clock.now().getTime() + afterSeconds * millisecondsPerSecond);
|
|
85
|
-
}
|
|
86
34
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { SimLambdaStreamDestinationConfiguration } from "./sim-lambda-stream-destination-config.js";
|
|
2
|
+
import type { SimLambdaDestinationTargets } from "../destination/sim-lambda-destination-targets.js";
|
|
1
3
|
import type { SimAwsAccountRegionScope } from "../../aws/sim-aws-account-region-scope.js";
|
|
2
4
|
import type { SimLambdaFunctionArn } from "../function/sim-lambda-function-configuration.js";
|
|
3
5
|
import type { SimLambdaStreamRetryLimits, SimLambdaStreamRetryLimitsConfiguration } from "./sim-lambda-stream-retry-limits.js";
|
|
@@ -31,6 +33,8 @@ interface SimLambdaEventSourceMappingProperties {
|
|
|
31
33
|
readonly enabled?: boolean | undefined;
|
|
32
34
|
readonly functionResponseTypes?: readonly SimLambdaFunctionResponseType[] | undefined;
|
|
33
35
|
readonly streamRetryLimits?: SimLambdaStreamRetryLimits | undefined;
|
|
36
|
+
readonly destinationConfig?: SimLambdaStreamDestinationConfiguration | undefined;
|
|
37
|
+
readonly destinations?: SimLambdaDestinationTargets | undefined;
|
|
34
38
|
readonly createdAt: Date;
|
|
35
39
|
}
|
|
36
40
|
/**
|
|
@@ -39,6 +43,7 @@ interface SimLambdaEventSourceMappingProperties {
|
|
|
39
43
|
* DeleteEventSourceMapping responses all report it.
|
|
40
44
|
*/
|
|
41
45
|
export interface SimLambdaEventSourceMappingConfiguration extends Partial<SimLambdaStreamRetryLimitsConfiguration> {
|
|
46
|
+
readonly DestinationConfig?: SimLambdaStreamDestinationConfiguration | undefined;
|
|
42
47
|
readonly UUID: string;
|
|
43
48
|
readonly EventSourceMappingArn: SimLambdaEventSourceMappingArn;
|
|
44
49
|
readonly EventSourceArn: string;
|
|
@@ -64,6 +69,7 @@ export interface SimLambdaEventSourceMappingConfiguration extends Partial<SimLam
|
|
|
64
69
|
*/
|
|
65
70
|
export declare class SimLambdaEventSourceMapping {
|
|
66
71
|
#private;
|
|
72
|
+
readonly destinations: SimLambdaDestinationTargets;
|
|
67
73
|
readonly uuid: string;
|
|
68
74
|
readonly eventSourceArn: string;
|
|
69
75
|
readonly functionName: string;
|
|
@@ -91,13 +97,14 @@ export declare class SimLambdaEventSourceMapping {
|
|
|
91
97
|
* the queue's own problem once the batch comes back.
|
|
92
98
|
*/
|
|
93
99
|
readonly streamRetryLimits: SimLambdaStreamRetryLimits | undefined;
|
|
100
|
+
private readonly destinationConfig;
|
|
94
101
|
private readonly accountRegionScope;
|
|
95
102
|
private readonly enabled;
|
|
96
103
|
private readonly lastModified;
|
|
97
104
|
constructor(properties: SimLambdaEventSourceMappingProperties);
|
|
98
|
-
/**
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
/** The configured failure queue or topic ARN. */
|
|
106
|
+
get failureDestinationArn(): string | undefined;
|
|
107
|
+
/** The ARN naming this mapping. */
|
|
101
108
|
get arn(): SimLambdaEventSourceMappingArn;
|
|
102
109
|
/**
|
|
103
110
|
* The state this mapping is in.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SimLambdaNoDestinationTargets } from "../destination/sim-lambda-destination-targets.js";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
/**
|
|
3
4
|
* One simulated Lambda event source mapping, from an event source to a
|
|
@@ -10,6 +11,7 @@ import { randomUUID } from "node:crypto";
|
|
|
10
11
|
* it.
|
|
11
12
|
*/
|
|
12
13
|
export class SimLambdaEventSourceMapping {
|
|
14
|
+
destinations;
|
|
13
15
|
uuid = randomUUID();
|
|
14
16
|
eventSourceArn;
|
|
15
17
|
functionName;
|
|
@@ -37,11 +39,15 @@ export class SimLambdaEventSourceMapping {
|
|
|
37
39
|
* the queue's own problem once the batch comes back.
|
|
38
40
|
*/
|
|
39
41
|
streamRetryLimits;
|
|
42
|
+
destinationConfig;
|
|
40
43
|
accountRegionScope;
|
|
41
44
|
enabled;
|
|
42
45
|
lastModified;
|
|
43
46
|
#state = "Creating";
|
|
44
47
|
constructor(properties) {
|
|
48
|
+
this.destinationConfig = properties.destinationConfig;
|
|
49
|
+
this.destinations =
|
|
50
|
+
properties.destinations ?? new SimLambdaNoDestinationTargets();
|
|
45
51
|
this.accountRegionScope = properties.accountRegionScope;
|
|
46
52
|
this.eventSourceArn = properties.eventSourceArn;
|
|
47
53
|
this.functionName = properties.functionName;
|
|
@@ -56,9 +62,11 @@ export class SimLambdaEventSourceMapping {
|
|
|
56
62
|
this.enabled = properties.enabled ?? true;
|
|
57
63
|
this.lastModified = properties.createdAt;
|
|
58
64
|
}
|
|
59
|
-
/**
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
/** The configured failure queue or topic ARN. */
|
|
66
|
+
get failureDestinationArn() {
|
|
67
|
+
return this.destinationConfig?.OnFailure?.Destination;
|
|
68
|
+
}
|
|
69
|
+
/** The ARN naming this mapping. */
|
|
62
70
|
get arn() {
|
|
63
71
|
const { regionName, accountId } = this.accountRegionScope;
|
|
64
72
|
return `arn:aws:lambda:${regionName}:${accountId}:event-source-mapping:${this.uuid}`;
|
|
@@ -96,6 +104,7 @@ export class SimLambdaEventSourceMapping {
|
|
|
96
104
|
*/
|
|
97
105
|
configuration() {
|
|
98
106
|
return {
|
|
107
|
+
DestinationConfig: structuredClone(this.destinationConfig),
|
|
99
108
|
UUID: this.uuid,
|
|
100
109
|
EventSourceMappingArn: this.arn,
|
|
101
110
|
EventSourceArn: this.eventSourceArn,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { type SimLambdaEventSourceRetryLimitsInput, SimLambdaStreamRetryLimits } from "./sim-lambda-stream-retry-limits.js";
|
|
2
2
|
/**
|
|
3
|
-
* Whether the event source a mapping names
|
|
3
|
+
* Whether the event source a mapping names decides for itself what becomes of
|
|
4
|
+
* a failed batch.
|
|
4
5
|
*
|
|
5
|
-
* A stream
|
|
6
|
-
* it, so the mapping is the only thing that decides when to
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* A stream leaves it to the mapping: a record stays on the stream whatever the
|
|
7
|
+
* function makes of it, so the mapping is the only thing that decides when to
|
|
8
|
+
* stop trying and whether to split the batch first. A queue does not, because a
|
|
9
|
+
* message the function never handles goes to the queue's own redrive policy,
|
|
10
|
+
* and real Lambda refuses a request that names any of the three for one.
|
|
10
11
|
*/
|
|
11
12
|
export interface SimLambdaEventSourceRetryLimitRules {
|
|
12
13
|
/**
|
|
@@ -23,7 +24,7 @@ export declare class SimLambdaNoRetryLimits implements SimLambdaEventSourceRetry
|
|
|
23
24
|
private readonly insteadDescription;
|
|
24
25
|
constructor(sourceDescription: string, insteadDescription: string);
|
|
25
26
|
/**
|
|
26
|
-
* Refuse
|
|
27
|
+
* Refuse all three, since this source is not the one counting.
|
|
27
28
|
*/
|
|
28
29
|
limitsIn(input: SimLambdaEventSourceRetryLimitsInput): SimLambdaStreamRetryLimits | undefined;
|
|
29
30
|
}
|
|
@@ -11,7 +11,7 @@ export class SimLambdaNoRetryLimits {
|
|
|
11
11
|
this.insteadDescription = insteadDescription;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* Refuse
|
|
14
|
+
* Refuse all three, since this source is not the one counting.
|
|
15
15
|
*/
|
|
16
16
|
limitsIn(input) {
|
|
17
17
|
const named = namedLimit(input);
|
|
@@ -40,7 +40,10 @@ function namedLimit(input) {
|
|
|
40
40
|
if (input.maximumRetryAttempts !== undefined) {
|
|
41
41
|
return "MaximumRetryAttempts";
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
if (input.maximumRecordAgeInSeconds !== undefined) {
|
|
44
|
+
return "MaximumRecordAgeInSeconds";
|
|
45
|
+
}
|
|
46
|
+
return input.bisectBatchOnFunctionError === undefined
|
|
44
47
|
? undefined
|
|
45
|
-
: "
|
|
48
|
+
: "BisectBatchOnFunctionError";
|
|
46
49
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface SimLambdaStreamDestinationConfiguration {
|
|
2
|
+
readonly OnFailure?: {
|
|
3
|
+
readonly Destination?: string | undefined;
|
|
4
|
+
} | undefined;
|
|
5
|
+
}
|
|
6
|
+
/** Validate the same destination shape for SDK and CloudFormation requests. */
|
|
7
|
+
export declare function simLambdaStreamDestinationConfig(value: unknown, sourceKind?: string): SimLambdaStreamDestinationConfiguration | undefined;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { isRecord } from "../../../util/type-guard/record.js";
|
|
2
|
+
import { SimLambdaDestinationArn } from "../destination/sim-lambda-destination-arn.js";
|
|
3
|
+
import { SimLambdaInvalidParameterValueException } from "../error/sim-lambda.error.js";
|
|
4
|
+
/** Validate the same destination shape for SDK and CloudFormation requests. */
|
|
5
|
+
export function simLambdaStreamDestinationConfig(value, sourceKind) {
|
|
6
|
+
if (value === undefined)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (sourceKind === "sqs") {
|
|
9
|
+
throw new SimLambdaInvalidParameterValueException("DestinationConfig is not supported for SQS event source mappings.");
|
|
10
|
+
}
|
|
11
|
+
if (!isRecord(value) ||
|
|
12
|
+
Object.keys(value).some((key) => key !== "OnFailure")) {
|
|
13
|
+
throw invalid();
|
|
14
|
+
}
|
|
15
|
+
const failure = value["OnFailure"];
|
|
16
|
+
if (failure === undefined)
|
|
17
|
+
return {};
|
|
18
|
+
if (!isRecord(failure) ||
|
|
19
|
+
Object.keys(failure).some((key) => key !== "Destination")) {
|
|
20
|
+
throw invalid();
|
|
21
|
+
}
|
|
22
|
+
const destination = failure["Destination"];
|
|
23
|
+
if (destination === undefined)
|
|
24
|
+
return { OnFailure: {} };
|
|
25
|
+
if (typeof destination !== "string")
|
|
26
|
+
throw invalid();
|
|
27
|
+
if (destination !== "") {
|
|
28
|
+
const arn = SimLambdaDestinationArn.of(destination);
|
|
29
|
+
if ((arn.service !== "sqs" && arn.service !== "sns") ||
|
|
30
|
+
arn.resource.endsWith(".fifo")) {
|
|
31
|
+
throw invalid();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { OnFailure: { Destination: destination } };
|
|
35
|
+
}
|
|
36
|
+
function invalid() {
|
|
37
|
+
return new SimLambdaInvalidParameterValueException("DestinationConfig supports only OnFailure with a standard SQS queue or SNS topic ARN.");
|
|
38
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
export interface SimLambdaEventSourceRetryLimitsInput {
|
|
10
10
|
readonly maximumRetryAttempts?: number | undefined;
|
|
11
11
|
readonly maximumRecordAgeInSeconds?: number | undefined;
|
|
12
|
+
readonly bisectBatchOnFunctionError?: boolean | undefined;
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
15
|
* The failed-batch limits a mapping reports back, as Lambda names them.
|
|
@@ -16,22 +17,29 @@ export interface SimLambdaEventSourceRetryLimitsInput {
|
|
|
16
17
|
export interface SimLambdaStreamRetryLimitsConfiguration {
|
|
17
18
|
readonly MaximumRetryAttempts: number;
|
|
18
19
|
readonly MaximumRecordAgeInSeconds: number;
|
|
20
|
+
readonly BisectBatchOnFunctionError: boolean;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
|
-
*
|
|
23
|
+
* What a stream mapping does with a batch its function keeps failing.
|
|
22
24
|
*
|
|
23
|
-
* The
|
|
24
|
-
* lifecycle
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* The three settings are one thing rather than three, because they run the same
|
|
26
|
+
* lifecycle. A failing batch is split around the record that broke it where the
|
|
27
|
+
* mapping was asked to bisect, and a record leaves the mapping when it has had
|
|
28
|
+
* its retries or when it is too old to be worth another, whichever comes first.
|
|
29
|
+
* The limits are held as Lambda states them, with `-1` for no limit, so a Get
|
|
30
|
+
* or a List reports back exactly what was asked for.
|
|
28
31
|
*/
|
|
29
32
|
export declare class SimLambdaStreamRetryLimits {
|
|
30
33
|
readonly maximumRetryAttempts: number;
|
|
31
34
|
readonly maximumRecordAgeInSeconds: number;
|
|
35
|
+
/**
|
|
36
|
+
* Whether a batch the function threw on is split in half and delivered again
|
|
37
|
+
* as two batches.
|
|
38
|
+
*/
|
|
39
|
+
readonly bisectBatchOnFunctionError: boolean;
|
|
32
40
|
constructor(input?: SimLambdaEventSourceRetryLimitsInput);
|
|
33
41
|
/**
|
|
34
|
-
* The
|
|
42
|
+
* The three settings as a Get, a List or a create response reports them.
|
|
35
43
|
*/
|
|
36
44
|
configuration(): SimLambdaStreamRetryLimitsConfiguration;
|
|
37
45
|
/**
|