@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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SimClock } from "../../../../util/clock/sim-clock.js";
|
|
2
|
+
import type { SimLambdaStreamRetryLimits } from "../sim-lambda-stream-retry-limits.js";
|
|
3
|
+
import type { SimLambdaEventSourceStreamPosition } from "../stream/sim-lambda-event-source-streams.js";
|
|
4
|
+
import type { SimLambdaStreamDiscard } from "./sim-lambda-stream-failure-record.js";
|
|
5
|
+
import type { SimLambdaStreamRecordTime } from "./sim-lambda-stream-record-times.js";
|
|
6
|
+
/** Identifies the expired prefix at the time a batch is polled. */
|
|
7
|
+
export declare class SimLambdaStreamBatchAge {
|
|
8
|
+
private readonly limits;
|
|
9
|
+
private readonly clock;
|
|
10
|
+
constructor(limits: SimLambdaStreamRetryLimits, clock: SimClock);
|
|
11
|
+
discarded(records: readonly SimLambdaStreamRecordTime[]): SimLambdaStreamDiscard | undefined;
|
|
12
|
+
firstLivePosition(records: readonly SimLambdaStreamRecordTime[], count: number): SimLambdaEventSourceStreamPosition;
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { assertDefined } from "../../../../util/type-guard/defined.js";
|
|
2
|
+
/** Identifies the expired prefix at the time a batch is polled. */
|
|
3
|
+
export class SimLambdaStreamBatchAge {
|
|
4
|
+
limits;
|
|
5
|
+
clock;
|
|
6
|
+
constructor(limits, clock) {
|
|
7
|
+
this.limits = limits;
|
|
8
|
+
this.clock = clock;
|
|
9
|
+
}
|
|
10
|
+
discarded(records) {
|
|
11
|
+
const at = this.clock.now();
|
|
12
|
+
const firstLive = records.findIndex((record) => !this.limits.hasAgedOut(record.at, at));
|
|
13
|
+
const count = firstLive === -1 ? records.length : firstLive;
|
|
14
|
+
if (count === 0)
|
|
15
|
+
return undefined;
|
|
16
|
+
return {
|
|
17
|
+
records: records.slice(0, count),
|
|
18
|
+
condition: "RecordAgeExceeded",
|
|
19
|
+
at,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
firstLivePosition(records, count) {
|
|
23
|
+
const sequenceNumber = records.at(count)?.sequenceNumber;
|
|
24
|
+
assertDefined(sequenceNumber, "live stream record sequence number");
|
|
25
|
+
return { kind: "sequence", sequenceNumber };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SimLambdaStreamFailureRecord } from "./sim-lambda-stream-failure-record.js";
|
|
2
|
+
import type { SimLambdaStreamRecordTime } from "./sim-lambda-stream-record-times.js";
|
|
3
|
+
export interface SimLambdaStreamBatchInfo {
|
|
4
|
+
readonly shardId: string;
|
|
5
|
+
readonly streamArn: string;
|
|
6
|
+
readonly startSequenceNumber: string;
|
|
7
|
+
readonly endSequenceNumber: string;
|
|
8
|
+
readonly approximateArrivalOfFirstRecord: string;
|
|
9
|
+
readonly approximateArrivalOfLastRecord: string;
|
|
10
|
+
readonly batchSize: number;
|
|
11
|
+
}
|
|
12
|
+
/** Identify the discarded records by shard and sequence-number bounds. */
|
|
13
|
+
export declare function simLambdaStreamBatchInfo(records: readonly SimLambdaStreamRecordTime[], streamArn: string, shardId: string | undefined): SimLambdaStreamBatchInfo;
|
|
14
|
+
/** Identify the discarded records by shard and sequence-number bounds. */
|
|
15
|
+
export declare function streamFailureBatchInfo(arn: string, info: SimLambdaStreamBatchInfo): Pick<SimLambdaStreamFailureRecord, "DDBStreamBatchInfo" | "KinesisBatchInfo">;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { assertDefined } from "../../../../util/type-guard/defined.js";
|
|
2
|
+
/** Identify the discarded records by shard and sequence-number bounds. */
|
|
3
|
+
export function simLambdaStreamBatchInfo(records, streamArn, shardId) {
|
|
4
|
+
const first = records.at(0);
|
|
5
|
+
const last = records.at(-1);
|
|
6
|
+
assertDefined(shardId, "discarded stream batch shard ID");
|
|
7
|
+
assertDefined(first?.sequenceNumber, "discarded batch start sequence number");
|
|
8
|
+
assertDefined(last?.sequenceNumber, "discarded batch end sequence number");
|
|
9
|
+
assertDefined(first.at, "discarded batch first arrival time");
|
|
10
|
+
assertDefined(last.at, "discarded batch last arrival time");
|
|
11
|
+
return {
|
|
12
|
+
shardId,
|
|
13
|
+
streamArn,
|
|
14
|
+
startSequenceNumber: first.sequenceNumber,
|
|
15
|
+
endSequenceNumber: last.sequenceNumber,
|
|
16
|
+
approximateArrivalOfFirstRecord: first.at.toISOString(),
|
|
17
|
+
approximateArrivalOfLastRecord: last.at.toISOString(),
|
|
18
|
+
batchSize: records.length,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Identify the discarded records by shard and sequence-number bounds. */
|
|
22
|
+
export function streamFailureBatchInfo(arn, info) {
|
|
23
|
+
if (arn.startsWith("arn:aws:dynamodb:"))
|
|
24
|
+
return { DDBStreamBatchInfo: info };
|
|
25
|
+
return { KinesisBatchInfo: info };
|
|
26
|
+
}
|
|
@@ -14,6 +14,7 @@ import type { SimLambdaStreamRecordTime } from "./sim-lambda-stream-record-times
|
|
|
14
14
|
* to and the instants its records are aged from.
|
|
15
15
|
*/
|
|
16
16
|
export declare class SimLambdaStreamBatchOutcome {
|
|
17
|
+
readonly functionError: boolean;
|
|
17
18
|
readonly isHandled: boolean;
|
|
18
19
|
/**
|
|
19
20
|
* The records the batch carried, in stream order.
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* to and the instants its records are aged from.
|
|
13
13
|
*/
|
|
14
14
|
export class SimLambdaStreamBatchOutcome {
|
|
15
|
+
functionError;
|
|
15
16
|
isHandled;
|
|
16
17
|
/**
|
|
17
18
|
* The records the batch carried, in stream order.
|
|
@@ -19,6 +20,7 @@ export class SimLambdaStreamBatchOutcome {
|
|
|
19
20
|
records;
|
|
20
21
|
rewindTo;
|
|
21
22
|
constructor(properties) {
|
|
23
|
+
this.functionError = properties.functionError ?? false;
|
|
22
24
|
this.isHandled = properties.isHandled;
|
|
23
25
|
this.records = properties.records;
|
|
24
26
|
this.rewindTo = properties.rewindTo;
|
|
@@ -33,7 +35,11 @@ export class SimLambdaStreamBatchOutcome {
|
|
|
33
35
|
* A batch the function did not take, which is read again from where it was.
|
|
34
36
|
*/
|
|
35
37
|
static failed(records) {
|
|
36
|
-
return new SimLambdaStreamBatchOutcome({
|
|
38
|
+
return new SimLambdaStreamBatchOutcome({
|
|
39
|
+
isHandled: false,
|
|
40
|
+
records,
|
|
41
|
+
functionError: true,
|
|
42
|
+
});
|
|
37
43
|
}
|
|
38
44
|
/**
|
|
39
45
|
* A batch the function reported failing partway through, which is read again
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SimLambdaFunction } from "../../function/sim-lambda-function.js";
|
|
2
|
+
import type { SimLambdaEventSourceStreamProgressBatch } from "../stream/sim-lambda-event-source-streams.js";
|
|
3
|
+
import type { SimLambdaStreamBatchOutcome } from "./sim-lambda-stream-batch-outcome.js";
|
|
4
|
+
import type { SimLambdaStreamProgress } from "./sim-lambda-stream-progress.js";
|
|
5
|
+
import type { SimLambdaStreamRecordTime } from "./sim-lambda-stream-record-times.js";
|
|
6
|
+
interface StreamBatchProcessing<RecordType> {
|
|
7
|
+
readonly batch: SimLambdaEventSourceStreamProgressBatch & {
|
|
8
|
+
readonly records: readonly RecordType[];
|
|
9
|
+
};
|
|
10
|
+
readonly simFunction: SimLambdaFunction;
|
|
11
|
+
readonly progress: SimLambdaStreamProgress;
|
|
12
|
+
readonly times: (records: readonly RecordType[]) => readonly SimLambdaStreamRecordTime[];
|
|
13
|
+
readonly deliver: (records: readonly RecordType[]) => Promise<SimLambdaStreamBatchOutcome>;
|
|
14
|
+
}
|
|
15
|
+
/** Check record age, invoke live records, and apply the batch outcome. */
|
|
16
|
+
export declare function processSimLambdaStreamBatch<RecordType>(properties: StreamBatchProcessing<RecordType>): Promise<void>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Check record age, invoke live records, and apply the batch outcome. */
|
|
2
|
+
export async function processSimLambdaStreamBatch(properties) {
|
|
3
|
+
const { batch, progress, simFunction } = properties;
|
|
4
|
+
if (batch.records.length === 0) {
|
|
5
|
+
progress.caughtUp(batch);
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const firstLive = await progress.before(properties.times(batch.records), batch, simFunction);
|
|
9
|
+
if (firstLive === batch.records.length)
|
|
10
|
+
return;
|
|
11
|
+
await progress.after(await properties.deliver(batch.records.slice(firstLive)), batch, simFunction);
|
|
12
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { SimLambdaStreamBatchOutcome } from "./sim-lambda-stream-batch-outcome.js";
|
|
2
|
+
/**
|
|
3
|
+
* How much of a failing batch the next delivery may carry.
|
|
4
|
+
*
|
|
5
|
+
* A mapping asked to bisect halves a batch its function threw on, and halves
|
|
6
|
+
* again on each further error, until a failing batch holds one record. That is
|
|
7
|
+
* how the record that broke the batch ends up delivered on its own, and how the
|
|
8
|
+
* records beside it get through.
|
|
9
|
+
*
|
|
10
|
+
* A split is progress rather than another attempt at the same work, so it puts
|
|
11
|
+
* the retry count back to the start. Without that the simulator's own cap of
|
|
12
|
+
* five attempts would discard a batch of a hundred long before it was down to
|
|
13
|
+
* one record. A batch halves at every step, so the splitting ends on its own,
|
|
14
|
+
* and the single record it ends on is then counted and discarded as any failing
|
|
15
|
+
* batch is.
|
|
16
|
+
*
|
|
17
|
+
* Two numbers say what the next read may take. The half is how many records a
|
|
18
|
+
* delivery may carry, and the remainder is how many records of the batch being
|
|
19
|
+
* split are still to get through. Reading the lower of the two is what keeps a
|
|
20
|
+
* record written while the splitting is going on out of it: the halves are the
|
|
21
|
+
* batch that failed, and a record that arrived afterwards belongs to the batch
|
|
22
|
+
* after it. The mapping's own batch size comes back once the whole of the split
|
|
23
|
+
* batch is through.
|
|
24
|
+
*/
|
|
25
|
+
export declare class SimLambdaStreamBisect {
|
|
26
|
+
#private;
|
|
27
|
+
private readonly enabled;
|
|
28
|
+
constructor(enabled: boolean);
|
|
29
|
+
/**
|
|
30
|
+
* How many records the next read may take, within the mapping's batch size.
|
|
31
|
+
*/
|
|
32
|
+
sizeWithin(batchSize: number): number;
|
|
33
|
+
/**
|
|
34
|
+
* Split a batch the function threw on, answering with whether it split.
|
|
35
|
+
*
|
|
36
|
+
* A batch the function reported partial failures on is left alone. Lambda
|
|
37
|
+
* bisects around an error the handler raised, and a report already says which
|
|
38
|
+
* record to go back to.
|
|
39
|
+
*/
|
|
40
|
+
split(outcome: SimLambdaStreamBatchOutcome): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Take records of the batch being split that the mapping is finished with,
|
|
43
|
+
* whether the function handled them, they were discarded, or they aged out.
|
|
44
|
+
*
|
|
45
|
+
* The whole of the split batch being through is what puts the mapping back on
|
|
46
|
+
* full batches.
|
|
47
|
+
*/
|
|
48
|
+
finished(count: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* Read whole batches again.
|
|
51
|
+
*/
|
|
52
|
+
reset(): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much of a failing batch the next delivery may carry.
|
|
3
|
+
*
|
|
4
|
+
* A mapping asked to bisect halves a batch its function threw on, and halves
|
|
5
|
+
* again on each further error, until a failing batch holds one record. That is
|
|
6
|
+
* how the record that broke the batch ends up delivered on its own, and how the
|
|
7
|
+
* records beside it get through.
|
|
8
|
+
*
|
|
9
|
+
* A split is progress rather than another attempt at the same work, so it puts
|
|
10
|
+
* the retry count back to the start. Without that the simulator's own cap of
|
|
11
|
+
* five attempts would discard a batch of a hundred long before it was down to
|
|
12
|
+
* one record. A batch halves at every step, so the splitting ends on its own,
|
|
13
|
+
* and the single record it ends on is then counted and discarded as any failing
|
|
14
|
+
* batch is.
|
|
15
|
+
*
|
|
16
|
+
* Two numbers say what the next read may take. The half is how many records a
|
|
17
|
+
* delivery may carry, and the remainder is how many records of the batch being
|
|
18
|
+
* split are still to get through. Reading the lower of the two is what keeps a
|
|
19
|
+
* record written while the splitting is going on out of it: the halves are the
|
|
20
|
+
* batch that failed, and a record that arrived afterwards belongs to the batch
|
|
21
|
+
* after it. The mapping's own batch size comes back once the whole of the split
|
|
22
|
+
* batch is through.
|
|
23
|
+
*/
|
|
24
|
+
export class SimLambdaStreamBisect {
|
|
25
|
+
enabled;
|
|
26
|
+
#half;
|
|
27
|
+
#remaining = 0;
|
|
28
|
+
constructor(enabled) {
|
|
29
|
+
this.enabled = enabled;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* How many records the next read may take, within the mapping's batch size.
|
|
33
|
+
*/
|
|
34
|
+
sizeWithin(batchSize) {
|
|
35
|
+
const half = this.#half;
|
|
36
|
+
return half === undefined
|
|
37
|
+
? batchSize
|
|
38
|
+
: Math.min(half, this.#remaining, batchSize);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Split a batch the function threw on, answering with whether it split.
|
|
42
|
+
*
|
|
43
|
+
* A batch the function reported partial failures on is left alone. Lambda
|
|
44
|
+
* bisects around an error the handler raised, and a report already says which
|
|
45
|
+
* record to go back to.
|
|
46
|
+
*/
|
|
47
|
+
split(outcome) {
|
|
48
|
+
const count = outcome.records.length;
|
|
49
|
+
if (!this.enabled || !outcome.functionError || count < 2) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
this.#half = Math.ceil(count / 2);
|
|
53
|
+
this.#remaining = count;
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Take records of the batch being split that the mapping is finished with,
|
|
58
|
+
* whether the function handled them, they were discarded, or they aged out.
|
|
59
|
+
*
|
|
60
|
+
* The whole of the split batch being through is what puts the mapping back on
|
|
61
|
+
* full batches.
|
|
62
|
+
*/
|
|
63
|
+
finished(count) {
|
|
64
|
+
if (this.#half === undefined || count <= 0) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
this.#remaining -= count;
|
|
68
|
+
if (this.#remaining <= 0) {
|
|
69
|
+
this.reset();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Read whole batches again.
|
|
74
|
+
*/
|
|
75
|
+
reset() {
|
|
76
|
+
this.#half = undefined;
|
|
77
|
+
this.#remaining = 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PollSchedule } from "../../../../util/background/poll-schedule.js";
|
|
2
|
+
import type { SimLambdaEventSourceStart } from "../sim-lambda-event-source-starting-position.js";
|
|
3
|
+
import type { SimLambdaEventSourceStreamPosition, SimLambdaEventSourceStreamProgressBatch } from "../stream/sim-lambda-event-source-streams.js";
|
|
4
|
+
import type { SimLambdaStreamRetryAttempt } from "./sim-lambda-stream-retry.js";
|
|
5
|
+
/** Keep the next read position and schedule consistent when a batch finishes or retries. */
|
|
6
|
+
export declare class SimLambdaStreamCursor {
|
|
7
|
+
private readonly schedule;
|
|
8
|
+
private readonly checkpoint;
|
|
9
|
+
constructor(start: SimLambdaEventSourceStart, schedule: PollSchedule);
|
|
10
|
+
get position(): SimLambdaEventSourceStreamPosition;
|
|
11
|
+
advanceTo(position: SimLambdaEventSourceStreamPosition): void;
|
|
12
|
+
pollNow(): void;
|
|
13
|
+
handled(batch: SimLambdaEventSourceStreamProgressBatch): void;
|
|
14
|
+
resume(attempt: SimLambdaStreamRetryAttempt): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SimLambdaStreamCheckpoint } from "./sim-lambda-stream-checkpoint.js";
|
|
2
|
+
/** Keep the next read position and schedule consistent when a batch finishes or retries. */
|
|
3
|
+
export class SimLambdaStreamCursor {
|
|
4
|
+
schedule;
|
|
5
|
+
checkpoint;
|
|
6
|
+
constructor(start, schedule) {
|
|
7
|
+
this.schedule = schedule;
|
|
8
|
+
this.checkpoint = new SimLambdaStreamCheckpoint(start);
|
|
9
|
+
}
|
|
10
|
+
get position() {
|
|
11
|
+
return this.checkpoint.position;
|
|
12
|
+
}
|
|
13
|
+
advanceTo(position) {
|
|
14
|
+
this.checkpoint.advanceTo(position);
|
|
15
|
+
}
|
|
16
|
+
pollNow() {
|
|
17
|
+
this.schedule.now();
|
|
18
|
+
}
|
|
19
|
+
handled(batch) {
|
|
20
|
+
this.advanceTo(batch.next);
|
|
21
|
+
if (!batch.drained)
|
|
22
|
+
this.pollNow();
|
|
23
|
+
}
|
|
24
|
+
resume(attempt) {
|
|
25
|
+
this.advanceTo(attempt.position);
|
|
26
|
+
this.schedule.afterSeconds(attempt.afterSeconds);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SimLambdaStreamBatchAge } from "./sim-lambda-stream-batch-age.js";
|
|
2
|
+
import type { SimLambdaStreamRecordTime } from "./sim-lambda-stream-record-times.js";
|
|
3
|
+
import type { SimLambdaFunction } from "../../function/sim-lambda-function.js";
|
|
4
|
+
import type { SimLambdaStreamFailureDestination } from "./sim-lambda-stream-failure-destination.js";
|
|
5
|
+
import type { SimLambdaEventSourceStreamProgressBatch } from "../stream/sim-lambda-event-source-streams.js";
|
|
6
|
+
import type { SimLambdaStreamCursor } from "./sim-lambda-stream-cursor.js";
|
|
7
|
+
interface StreamExpiryProperties {
|
|
8
|
+
readonly age: SimLambdaStreamBatchAge;
|
|
9
|
+
readonly cursor: SimLambdaStreamCursor;
|
|
10
|
+
readonly failures: SimLambdaStreamFailureDestination;
|
|
11
|
+
readonly handled: (batch: SimLambdaEventSourceStreamProgressBatch) => void;
|
|
12
|
+
}
|
|
13
|
+
/** Advance past expired records and notify their destination before processing live records. */
|
|
14
|
+
export declare class SimLambdaStreamExpiry {
|
|
15
|
+
private readonly properties;
|
|
16
|
+
constructor(properties: StreamExpiryProperties);
|
|
17
|
+
before(records: readonly SimLambdaStreamRecordTime[], batch: SimLambdaEventSourceStreamProgressBatch, simFunction: SimLambdaFunction): Promise<number>;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Advance past expired records and notify their destination before processing live records. */
|
|
2
|
+
export class SimLambdaStreamExpiry {
|
|
3
|
+
properties;
|
|
4
|
+
constructor(properties) {
|
|
5
|
+
this.properties = properties;
|
|
6
|
+
}
|
|
7
|
+
async before(records, batch, simFunction) {
|
|
8
|
+
const { age, cursor, failures, handled } = this.properties;
|
|
9
|
+
const discard = age.discarded(records);
|
|
10
|
+
if (discard === undefined)
|
|
11
|
+
return 0;
|
|
12
|
+
const discardedCount = discard.records.length;
|
|
13
|
+
const notification = failures.deliver(discard, batch, simFunction);
|
|
14
|
+
if (discardedCount === records.length) {
|
|
15
|
+
handled(batch);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
cursor.advanceTo(age.firstLivePosition(records, discardedCount));
|
|
19
|
+
}
|
|
20
|
+
await notification;
|
|
21
|
+
return discardedCount;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SimLambdaStreamFailureRecord, StreamFailureRecordProperties } from "./sim-lambda-stream-failure-record.js";
|
|
2
|
+
/** Build invocation metadata for a stream failure notification. */
|
|
3
|
+
export declare function streamFailureContext(properties: StreamFailureRecordProperties): Pick<SimLambdaStreamFailureRecord, "requestContext" | "responseContext">;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
/** Build invocation metadata for a stream failure notification. */
|
|
3
|
+
export function streamFailureContext(properties) {
|
|
4
|
+
return {
|
|
5
|
+
requestContext: {
|
|
6
|
+
requestId: randomUUID(),
|
|
7
|
+
functionArn: properties.mapping.functionArn,
|
|
8
|
+
condition: properties.discard.condition,
|
|
9
|
+
approximateInvokeCount: properties.invokeCount,
|
|
10
|
+
},
|
|
11
|
+
...(properties.invokeCount > 0 && {
|
|
12
|
+
responseContext: {
|
|
13
|
+
statusCode: 200,
|
|
14
|
+
executedVersion: properties.simFunction.version,
|
|
15
|
+
...(properties.functionError && { functionError: "Unhandled" }),
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SimLambdaStreamBatchOutcome } from "./sim-lambda-stream-batch-outcome.js";
|
|
2
|
+
import type { SimLambdaFunction } from "../../function/sim-lambda-function.js";
|
|
3
|
+
import type { SimLambdaEventSourceMapping } from "../sim-lambda-event-source-mapping.js";
|
|
4
|
+
import type { SimLambdaEventSourceStreamProgressBatch } from "../stream/sim-lambda-event-source-streams.js";
|
|
5
|
+
import { type SimLambdaStreamDiscard } from "./sim-lambda-stream-failure-record.js";
|
|
6
|
+
/** Count invocations and send discarded batch metadata through the destination service. */
|
|
7
|
+
export declare class SimLambdaStreamFailureDestination {
|
|
8
|
+
private readonly mapping;
|
|
9
|
+
private invokeCount;
|
|
10
|
+
private functionError;
|
|
11
|
+
constructor(mapping: SimLambdaEventSourceMapping);
|
|
12
|
+
invoked(outcome: SimLambdaStreamBatchOutcome): void;
|
|
13
|
+
reset(): void;
|
|
14
|
+
deliver(discard: SimLambdaStreamDiscard | undefined, batch: SimLambdaEventSourceStreamProgressBatch, simFunction: SimLambdaFunction): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SimLambdaDestinationArn } from "../../destination/sim-lambda-destination-arn.js";
|
|
2
|
+
import { simLambdaStreamFailureRecord, } from "./sim-lambda-stream-failure-record.js";
|
|
3
|
+
/** Count invocations and send discarded batch metadata through the destination service. */
|
|
4
|
+
export class SimLambdaStreamFailureDestination {
|
|
5
|
+
mapping;
|
|
6
|
+
invokeCount = 0;
|
|
7
|
+
functionError = false;
|
|
8
|
+
constructor(mapping) {
|
|
9
|
+
this.mapping = mapping;
|
|
10
|
+
}
|
|
11
|
+
invoked(outcome) {
|
|
12
|
+
this.invokeCount += 1;
|
|
13
|
+
this.functionError = outcome.functionError;
|
|
14
|
+
}
|
|
15
|
+
reset() {
|
|
16
|
+
this.invokeCount = 0;
|
|
17
|
+
}
|
|
18
|
+
async deliver(discard, batch, simFunction) {
|
|
19
|
+
const mapping = this.mapping;
|
|
20
|
+
const arn = mapping.failureDestinationArn;
|
|
21
|
+
if (discard === undefined || arn === undefined || arn === "")
|
|
22
|
+
return;
|
|
23
|
+
const record = simLambdaStreamFailureRecord({
|
|
24
|
+
mapping,
|
|
25
|
+
simFunction,
|
|
26
|
+
discard,
|
|
27
|
+
invokeCount: this.invokeCount,
|
|
28
|
+
shardId: batch.shardId,
|
|
29
|
+
functionError: this.functionError,
|
|
30
|
+
});
|
|
31
|
+
await mapping.destinations.deliver({
|
|
32
|
+
destinationArn: SimLambdaDestinationArn.of(arn),
|
|
33
|
+
sourceFunctionArn: mapping.functionArn,
|
|
34
|
+
sourceFunctionRoleArn: simFunction.roleArn,
|
|
35
|
+
record,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type SimLambdaStreamBatchInfo } from "./sim-lambda-stream-batch-info.js";
|
|
2
|
+
import type { SimLambdaFunction } from "../../function/sim-lambda-function.js";
|
|
3
|
+
import type { SimLambdaEventSourceMapping } from "../sim-lambda-event-source-mapping.js";
|
|
4
|
+
import type { SimLambdaStreamRecordTime } from "./sim-lambda-stream-record-times.js";
|
|
5
|
+
export type SimLambdaStreamFailureCondition = "RetryAttemptsExhausted" | "RecordAgeExceeded";
|
|
6
|
+
export interface SimLambdaStreamDiscard {
|
|
7
|
+
readonly records: readonly SimLambdaStreamRecordTime[];
|
|
8
|
+
readonly condition: SimLambdaStreamFailureCondition;
|
|
9
|
+
readonly at: Date;
|
|
10
|
+
}
|
|
11
|
+
export interface SimLambdaStreamFailureRecord {
|
|
12
|
+
readonly version: string;
|
|
13
|
+
readonly timestamp: string;
|
|
14
|
+
readonly requestContext: {
|
|
15
|
+
readonly requestId: string;
|
|
16
|
+
readonly functionArn: string;
|
|
17
|
+
readonly condition: SimLambdaStreamFailureCondition;
|
|
18
|
+
readonly approximateInvokeCount: number;
|
|
19
|
+
};
|
|
20
|
+
readonly responseContext?: {
|
|
21
|
+
readonly statusCode: number;
|
|
22
|
+
readonly executedVersion: string;
|
|
23
|
+
readonly functionError?: string;
|
|
24
|
+
};
|
|
25
|
+
readonly DDBStreamBatchInfo?: SimLambdaStreamBatchInfo;
|
|
26
|
+
readonly KinesisBatchInfo?: SimLambdaStreamBatchInfo;
|
|
27
|
+
}
|
|
28
|
+
export interface StreamFailureRecordProperties {
|
|
29
|
+
readonly mapping: SimLambdaEventSourceMapping;
|
|
30
|
+
readonly simFunction: SimLambdaFunction;
|
|
31
|
+
readonly shardId: string | undefined;
|
|
32
|
+
readonly discard: SimLambdaStreamDiscard;
|
|
33
|
+
readonly invokeCount: number;
|
|
34
|
+
readonly functionError: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* SQS and SNS receive metadata identifying the discarded records.
|
|
38
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/services-dynamodb-errors.html
|
|
39
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/kinesis-on-failure-destination.html
|
|
40
|
+
*/
|
|
41
|
+
export declare function simLambdaStreamFailureRecord(properties: StreamFailureRecordProperties): SimLambdaStreamFailureRecord;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { streamFailureContext } from "./sim-lambda-stream-failure-context.js";
|
|
2
|
+
import { simLambdaStreamBatchInfo, streamFailureBatchInfo, } from "./sim-lambda-stream-batch-info.js";
|
|
3
|
+
/**
|
|
4
|
+
* SQS and SNS receive metadata identifying the discarded records.
|
|
5
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/services-dynamodb-errors.html
|
|
6
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/kinesis-on-failure-destination.html
|
|
7
|
+
*/
|
|
8
|
+
export function simLambdaStreamFailureRecord(properties) {
|
|
9
|
+
const { mapping, discard, shardId } = properties;
|
|
10
|
+
const info = simLambdaStreamBatchInfo(discard.records, mapping.eventSourceArn, shardId);
|
|
11
|
+
return {
|
|
12
|
+
version: "1.0",
|
|
13
|
+
timestamp: discard.at.toISOString(),
|
|
14
|
+
...streamFailureContext(properties),
|
|
15
|
+
...streamFailureBatchInfo(mapping.eventSourceArn, info),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SimLambdaStreamExpiry } from "./sim-lambda-stream-expiry.js";
|
|
2
|
+
import { SimLambdaStreamFailureDestination } from "./sim-lambda-stream-failure-destination.js";
|
|
3
|
+
import { SimLambdaStreamCursor } from "./sim-lambda-stream-cursor.js";
|
|
4
|
+
import { SimLambdaStreamRetry } from "./sim-lambda-stream-retry.js";
|
|
5
|
+
import { SimLambdaStreamBisect } from "./sim-lambda-stream-bisect.js";
|
|
6
|
+
import type { BackgroundScheduler, BackgroundTask } from "../../../../util/background/background.js";
|
|
7
|
+
import type { SimLambdaEventSourceMapping } from "../sim-lambda-event-source-mapping.js";
|
|
8
|
+
import type { SimLambdaEventSourceStreamProgressBatch } from "../stream/sim-lambda-event-source-streams.js";
|
|
9
|
+
export interface SimLambdaStreamProgressProperties {
|
|
10
|
+
readonly mapping: SimLambdaEventSourceMapping;
|
|
11
|
+
readonly background: BackgroundScheduler;
|
|
12
|
+
readonly poll: BackgroundTask;
|
|
13
|
+
}
|
|
14
|
+
/** Own the per-shard retry state and its expiry and destination collaborators. */
|
|
15
|
+
export declare class SimLambdaStreamProgressState {
|
|
16
|
+
readonly expiry: SimLambdaStreamExpiry;
|
|
17
|
+
readonly failures: SimLambdaStreamFailureDestination;
|
|
18
|
+
readonly cursor: SimLambdaStreamCursor;
|
|
19
|
+
readonly retry: SimLambdaStreamRetry;
|
|
20
|
+
readonly bisect: SimLambdaStreamBisect;
|
|
21
|
+
constructor(properties: SimLambdaStreamProgressProperties);
|
|
22
|
+
handled(batch: SimLambdaEventSourceStreamProgressBatch): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SimLambdaStreamExpiry } from "./sim-lambda-stream-expiry.js";
|
|
2
|
+
import { SimLambdaStreamBatchAge } from "./sim-lambda-stream-batch-age.js";
|
|
3
|
+
import { SimLambdaStreamFailureDestination } from "./sim-lambda-stream-failure-destination.js";
|
|
4
|
+
import { SimLambdaStreamCursor } from "./sim-lambda-stream-cursor.js";
|
|
5
|
+
import { SimLambdaStreamRetry } from "./sim-lambda-stream-retry.js";
|
|
6
|
+
import { SimLambdaStreamBisect } from "./sim-lambda-stream-bisect.js";
|
|
7
|
+
import { PollSchedule } from "../../../../util/background/poll-schedule.js";
|
|
8
|
+
import { assertDefined } from "../../../../util/type-guard/defined.js";
|
|
9
|
+
/** Own the per-shard retry state and its expiry and destination collaborators. */
|
|
10
|
+
export class SimLambdaStreamProgressState {
|
|
11
|
+
expiry;
|
|
12
|
+
failures;
|
|
13
|
+
cursor;
|
|
14
|
+
retry;
|
|
15
|
+
bisect;
|
|
16
|
+
constructor(properties) {
|
|
17
|
+
const { mapping, background } = properties;
|
|
18
|
+
this.failures = new SimLambdaStreamFailureDestination(mapping);
|
|
19
|
+
// A stream mapping is refused at creation unless it names a starting
|
|
20
|
+
// position, so one that has got this far without one is the simulator
|
|
21
|
+
// having gone wrong rather than a request having been wrong.
|
|
22
|
+
const { start, streamRetryLimits } = mapping;
|
|
23
|
+
assertDefined(start, "stream mapping start position");
|
|
24
|
+
assertDefined(streamRetryLimits, "stream mapping retry limits");
|
|
25
|
+
this.cursor = new SimLambdaStreamCursor(start, new PollSchedule(properties));
|
|
26
|
+
this.retry = new SimLambdaStreamRetry(streamRetryLimits, background);
|
|
27
|
+
this.bisect = new SimLambdaStreamBisect(streamRetryLimits.bisectBatchOnFunctionError);
|
|
28
|
+
this.expiry = new SimLambdaStreamExpiry({
|
|
29
|
+
age: new SimLambdaStreamBatchAge(streamRetryLimits, background),
|
|
30
|
+
cursor: this.cursor,
|
|
31
|
+
failures: this.failures,
|
|
32
|
+
handled: (batch) => {
|
|
33
|
+
this.handled(batch);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
handled(batch) {
|
|
38
|
+
this.failures.reset();
|
|
39
|
+
this.retry.reset();
|
|
40
|
+
this.cursor.handled(batch);
|
|
41
|
+
}
|
|
42
|
+
}
|