@kensio/yulin 1.21.20 → 1.21.22
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/athena/engine/sim-athena-engine-result.d.ts +9 -1
- package/dist/service/athena/engine/sim-athena-engine-result.js +15 -4
- package/dist/service/athena/engine/sim-athena-engine-run.d.ts +2 -0
- package/dist/service/athena/engine/sim-athena-engine-run.js +6 -1
- package/dist/service/athena/engine/sim-athena-query-engine.js +1 -0
- package/dist/service/athena/engine/sim-athena-result-columns.d.ts +1 -1
- package/dist/service/athena/engine/sim-athena-result-columns.js +11 -4
- package/dist/service/athena/engine/sim-athena-round-scales.d.ts +19 -0
- package/dist/service/athena/engine/sim-athena-round-scales.js +80 -0
- package/dist/service/athena/engine/sim-athena-sql-translation.d.ts +9 -0
- package/dist/service/athena/engine/sim-athena-sql-translation.js +17 -2
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +2 -0
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-names.js +1 -5
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.d.ts +5 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.js +7 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-refusals.js +0 -1
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.js +1 -0
- package/dist/service/lambda/command/event-source-mapping/event-source-mapping.command.d.ts +2 -1
- package/dist/service/lambda/command/event-source-mapping/event-source-mapping.command.js +0 -6
- package/dist/service/lambda/event-source/filter/sim-lambda-filter-criteria.d.ts +48 -0
- package/dist/service/lambda/event-source/filter/sim-lambda-filter-criteria.js +129 -0
- package/dist/service/lambda/event-source/filter/sim-lambda-filtered-delivery.d.ts +27 -0
- package/dist/service/lambda/event-source/filter/sim-lambda-filtered-delivery.js +15 -0
- package/dist/service/lambda/event-source/filter/sim-lambda-filtered-records.d.ts +24 -0
- package/dist/service/lambda/event-source/filter/sim-lambda-filtered-records.js +35 -0
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.d.ts +7 -4
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.js +9 -6
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-delivery.d.ts +16 -4
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-delivery.js +36 -5
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-event-source-poller.d.ts +4 -3
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-event-source-poller.js +6 -7
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-event.d.ts +14 -2
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-event.js +21 -2
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-delivery.d.ts +19 -6
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-delivery.js +41 -7
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.d.ts +7 -3
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.js +10 -9
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event.d.ts +6 -2
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event.js +6 -2
- package/dist/service/lambda/event-source/poll/sim-lambda-event-source-delivery.d.ts +21 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-event-source-delivery.js +32 -2
- package/dist/service/lambda/event-source/poll/sim-lambda-sqs-delivery.js +1 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-sqs-event.d.ts +8 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-sqs-event.js +11 -0
- package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.d.ts +10 -0
- package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.js +11 -0
- package/dist/service/lambda/event-source/stream/sim-lambda-stream-cascade-guard.d.ts +35 -8
- package/dist/service/lambda/event-source/stream/sim-lambda-stream-cascade-guard.js +35 -12
- package/dist/service/lambda/event-source/stream/sim-lambda-stream-cascade.error.d.ts +13 -4
- package/dist/service/lambda/event-source/stream/sim-lambda-stream-cascade.error.js +12 -6
- package/dist/service/lambda/event-source/stream/sim-lambda-stream-halt.d.ts +18 -0
- package/dist/service/lambda/event-source/stream/sim-lambda-stream-halt.js +22 -0
- package/dist/service/lambda/function/invoke/sim-lambda-invocation-deadline.d.ts +4 -0
- package/dist/service/lambda/function/invoke/sim-lambda-invocation-deadline.js +21 -0
- package/dist/service/lambda/function/invoke/sim-lambda-stall-watch.d.ts +38 -0
- package/dist/service/lambda/function/invoke/sim-lambda-stall-watch.js +78 -0
- package/dist/service/lambda/function/invoke/sim-lambda-stalled.error.d.ts +23 -0
- package/dist/service/lambda/function/invoke/sim-lambda-stalled.error.js +22 -0
- package/dist/service/lambda/function/invoke/timer/sim-lambda-clock-timer.d.ts +4 -0
- package/dist/service/lambda/function/invoke/timer/sim-lambda-clock-timer.js +8 -0
- package/dist/service/lambda/function/invoke/timer/sim-lambda-invocation-timers.d.ts +10 -0
- package/dist/service/lambda/function/invoke/timer/sim-lambda-invocation-timers.js +28 -0
- package/dist/service/lambda/function/invoke/timer/sim-lambda-pending-timer.d.ts +9 -0
- package/dist/service/lambda/function/invoke/timer/sim-lambda-pending-timer.js +1 -0
- package/dist/service/scheduler/command/schedule/schedule.command.d.ts +1 -0
- package/dist/service/scheduler/command/schedule/sim-scheduler-described-schedule.js +1 -0
- package/dist/service/scheduler/command/schedule/sim-scheduler-schedule-writer.js +2 -1
- package/dist/service/scheduler/command/schedule/sim-scheduler-unsimulated-input.d.ts +3 -3
- package/dist/service/scheduler/command/schedule/sim-scheduler-unsimulated-input.js +19 -11
- package/dist/service/scheduler/schedule/sim-scheduler-schedule-expression.d.ts +5 -3
- package/dist/service/scheduler/schedule/sim-scheduler-schedule-expression.js +6 -4
- package/dist/service/scheduler/schedule/sim-scheduler-schedule.d.ts +9 -0
- package/dist/service/scheduler/schedule/sim-scheduler-schedule.js +8 -0
- package/dist/util/schedule/at/sim-at-expression.d.ts +2 -1
- package/dist/util/schedule/at/sim-at-expression.js +7 -3
- package/dist/util/schedule/cron/sim-cron-expression.d.ts +6 -3
- package/dist/util/schedule/cron/sim-cron-expression.js +24 -21
- package/dist/util/schedule/sim-schedule-zone-clock.d.ts +26 -0
- package/dist/util/schedule/sim-schedule-zone-clock.js +56 -0
- package/dist/util/schedule/sim-schedule-zone.d.ts +58 -0
- package/dist/util/schedule/sim-schedule-zone.js +83 -0
- package/dist/util/schedule/sim-schedule.d.ts +1 -1
- package/dist/util/schedule/sim-schedule.js +6 -5
- package/docs/services/athena/README.md +5 -0
- package/docs/services/lambda/README.md +159 -15
- package/docs/services/scheduler/README.md +35 -6
- package/docs/time/README.md +6 -0
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SimLambdaFunction } from "../../function/sim-lambda-function.js";
|
|
2
2
|
import type { SimSqsPollMessage } from "../../../sqs/poll/sim-sqs-poll-message.js";
|
|
3
|
-
import
|
|
3
|
+
import { SimLambdaEventSourceBatchOutcome, type SimLambdaEventSourceBatchResponse } from "./sim-lambda-event-source-batch-response.js";
|
|
4
|
+
import type { SimLambdaFilterCriteria } from "../filter/sim-lambda-filter-criteria.js";
|
|
4
5
|
/**
|
|
5
6
|
* One record of an event source event.
|
|
6
7
|
*
|
|
@@ -25,10 +26,16 @@ export interface SimLambdaEventSourceEvent {
|
|
|
25
26
|
*/
|
|
26
27
|
export interface SimLambdaEventSourceEventBuilder {
|
|
27
28
|
of(messages: readonly SimSqsPollMessage[]): SimLambdaEventSourceEvent;
|
|
29
|
+
/**
|
|
30
|
+
* What a mapping's filters read one message as, which is the source's own
|
|
31
|
+
* translation.
|
|
32
|
+
*/
|
|
33
|
+
filterDocumentOf(message: SimSqsPollMessage): Record<string, unknown>;
|
|
28
34
|
}
|
|
29
35
|
interface SimLambdaEventSourceDeliveryProperties {
|
|
30
36
|
readonly eventBuilder: SimLambdaEventSourceEventBuilder;
|
|
31
37
|
readonly batchResponse: SimLambdaEventSourceBatchResponse;
|
|
38
|
+
readonly filterCriteria: SimLambdaFilterCriteria | undefined;
|
|
32
39
|
}
|
|
33
40
|
/**
|
|
34
41
|
* Hands one batch to a function and reads what became of it.
|
|
@@ -43,10 +50,23 @@ interface SimLambdaEventSourceDeliveryProperties {
|
|
|
43
50
|
export declare class SimLambdaEventSourceDelivery {
|
|
44
51
|
private readonly eventBuilder;
|
|
45
52
|
private readonly batchResponse;
|
|
53
|
+
private readonly filterCriteria;
|
|
46
54
|
constructor(properties: SimLambdaEventSourceDeliveryProperties);
|
|
47
55
|
/**
|
|
48
56
|
* Deliver a batch, answering with what to delete and what to leave.
|
|
49
57
|
*/
|
|
50
58
|
to(simFunction: SimLambdaFunction, messages: readonly SimSqsPollMessage[]): Promise<SimLambdaEventSourceBatchOutcome>;
|
|
59
|
+
/**
|
|
60
|
+
* One batch of matching messages, handed over and read back.
|
|
61
|
+
*/
|
|
62
|
+
private invoked;
|
|
63
|
+
/**
|
|
64
|
+
* An outcome with the filtered-out messages counted as handled, which deletes
|
|
65
|
+
* them whatever the function said about the rest.
|
|
66
|
+
*
|
|
67
|
+
* A message the function never saw is in neither list the outcome carries,
|
|
68
|
+
* which is what picks it out of the batch that was read.
|
|
69
|
+
*/
|
|
70
|
+
private alsoHandling;
|
|
51
71
|
}
|
|
52
72
|
export {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SimLambdaEventSourceBatchOutcome, } from "./sim-lambda-event-source-batch-response.js";
|
|
2
|
+
import { simLambdaFilteredDelivery } from "../filter/sim-lambda-filtered-delivery.js";
|
|
1
3
|
/**
|
|
2
4
|
* Hands one batch to a function and reads what became of it.
|
|
3
5
|
*
|
|
@@ -11,22 +13,50 @@
|
|
|
11
13
|
export class SimLambdaEventSourceDelivery {
|
|
12
14
|
eventBuilder;
|
|
13
15
|
batchResponse;
|
|
16
|
+
filterCriteria;
|
|
14
17
|
constructor(properties) {
|
|
15
18
|
this.eventBuilder = properties.eventBuilder;
|
|
16
19
|
this.batchResponse = properties.batchResponse;
|
|
20
|
+
this.filterCriteria = properties.filterCriteria;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* Deliver a batch, answering with what to delete and what to leave.
|
|
20
24
|
*/
|
|
21
25
|
async to(simFunction, messages) {
|
|
26
|
+
return await simLambdaFilteredDelivery({
|
|
27
|
+
criteria: this.filterCriteria,
|
|
28
|
+
records: messages,
|
|
29
|
+
documentOf: (message) => this.eventBuilder.filterDocumentOf(message),
|
|
30
|
+
// A message the filters excluded is deleted from the queue without the
|
|
31
|
+
// function seeing it, the way real Lambda deletes one.
|
|
32
|
+
handled: () => new SimLambdaEventSourceBatchOutcome(messages, []),
|
|
33
|
+
invoke: async (delivered) => this.alsoHandling(messages, await this.invoked(simFunction, delivered)),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* One batch of matching messages, handed over and read back.
|
|
38
|
+
*/
|
|
39
|
+
async invoked(simFunction, delivered) {
|
|
22
40
|
try {
|
|
23
|
-
return this.batchResponse.handled(
|
|
41
|
+
return this.batchResponse.handled(delivered, await simFunction.invoke(this.eventBuilder.of(delivered)));
|
|
24
42
|
}
|
|
25
43
|
catch {
|
|
26
44
|
// As on real Lambda, the handler error goes to the function's logs and
|
|
27
45
|
// not to whoever sent the message. What the sender sees is the batch
|
|
28
46
|
// coming back to the source.
|
|
29
|
-
return this.batchResponse.failed(
|
|
47
|
+
return this.batchResponse.failed(delivered);
|
|
30
48
|
}
|
|
31
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* An outcome with the filtered-out messages counted as handled, which deletes
|
|
52
|
+
* them whatever the function said about the rest.
|
|
53
|
+
*
|
|
54
|
+
* A message the function never saw is in neither list the outcome carries,
|
|
55
|
+
* which is what picks it out of the batch that was read.
|
|
56
|
+
*/
|
|
57
|
+
alsoHandling(messages, outcome) {
|
|
58
|
+
const seen = new Set([...outcome.handled, ...outcome.returned]);
|
|
59
|
+
const excluded = messages.filter((message) => !seen.has(message));
|
|
60
|
+
return new SimLambdaEventSourceBatchOutcome([...outcome.handled, ...excluded], outcome.returned);
|
|
61
|
+
}
|
|
32
62
|
}
|
|
@@ -12,5 +12,6 @@ export function makeSimLambdaSqsDelivery(properties) {
|
|
|
12
12
|
return new SimLambdaEventSourceDelivery({
|
|
13
13
|
eventBuilder: new SimLambdaSqsEventBuilder(properties.eventSourceArn),
|
|
14
14
|
batchResponse: new SimLambdaSqsBatchResponse(properties.mapping.reportsBatchItemFailures),
|
|
15
|
+
filterCriteria: properties.mapping.filterCriteria,
|
|
15
16
|
});
|
|
16
17
|
}
|
|
@@ -50,6 +50,14 @@ export declare class SimLambdaSqsEventBuilder {
|
|
|
50
50
|
* The event for a batch of messages.
|
|
51
51
|
*/
|
|
52
52
|
of(messages: readonly SimSqsPollMessage[]): SimLambdaSqsEvent;
|
|
53
|
+
/**
|
|
54
|
+
* What a mapping's filters read one message as.
|
|
55
|
+
*
|
|
56
|
+
* Real Lambda filters an SQS message on its body alone, and reads the body as
|
|
57
|
+
* JSON where it holds JSON. Nothing else about the message is here, because a
|
|
58
|
+
* pattern naming anything else was refused when the mapping was created.
|
|
59
|
+
*/
|
|
60
|
+
filterDocumentOf(message: SimSqsPollMessage): Record<string, unknown>;
|
|
53
61
|
private record;
|
|
54
62
|
private messageAttributes;
|
|
55
63
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { simLambdaFilterData } from "../filter/sim-lambda-filtered-records.js";
|
|
1
2
|
/**
|
|
2
3
|
* Builds the SQS event for one batch of polled messages.
|
|
3
4
|
*
|
|
@@ -17,6 +18,16 @@ export class SimLambdaSqsEventBuilder {
|
|
|
17
18
|
of(messages) {
|
|
18
19
|
return { Records: messages.map((message) => this.record(message)) };
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* What a mapping's filters read one message as.
|
|
23
|
+
*
|
|
24
|
+
* Real Lambda filters an SQS message on its body alone, and reads the body as
|
|
25
|
+
* JSON where it holds JSON. Nothing else about the message is here, because a
|
|
26
|
+
* pattern naming anything else was refused when the mapping was created.
|
|
27
|
+
*/
|
|
28
|
+
filterDocumentOf(message) {
|
|
29
|
+
return { body: simLambdaFilterData(message.Body) };
|
|
30
|
+
}
|
|
20
31
|
record(message) {
|
|
21
32
|
return {
|
|
22
33
|
messageId: message.MessageId,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SimLambdaStreamDestinationConfiguration } from "./sim-lambda-stream-destination-config.js";
|
|
2
2
|
import type { SimLambdaDestinationTargets } from "../destination/sim-lambda-destination-targets.js";
|
|
3
3
|
import type { SimAwsAccountRegionScope } from "../../aws/sim-aws-account-region-scope.js";
|
|
4
|
+
import type { SimLambdaFilterCriteria, SimLambdaFilterCriteriaInput } from "./filter/sim-lambda-filter-criteria.js";
|
|
4
5
|
import type { SimLambdaFunctionArn } from "../function/sim-lambda-function-configuration.js";
|
|
5
6
|
import type { SimLambdaStreamRetryLimits, SimLambdaStreamRetryLimitsConfiguration } from "./sim-lambda-stream-retry-limits.js";
|
|
6
7
|
import type { SimLambdaEventSourceStart, SimLambdaEventSourceStartingPosition } from "./sim-lambda-event-source-starting-position.js";
|
|
@@ -35,6 +36,7 @@ interface SimLambdaEventSourceMappingProperties {
|
|
|
35
36
|
readonly streamRetryLimits?: SimLambdaStreamRetryLimits | undefined;
|
|
36
37
|
readonly destinationConfig?: SimLambdaStreamDestinationConfiguration | undefined;
|
|
37
38
|
readonly destinations?: SimLambdaDestinationTargets | undefined;
|
|
39
|
+
readonly filterCriteria?: SimLambdaFilterCriteria | undefined;
|
|
38
40
|
readonly createdAt: Date;
|
|
39
41
|
}
|
|
40
42
|
/**
|
|
@@ -53,6 +55,7 @@ export interface SimLambdaEventSourceMappingConfiguration extends Partial<SimLam
|
|
|
53
55
|
readonly StartingPositionTimestamp?: Date | undefined;
|
|
54
56
|
readonly MaximumBatchingWindowInSeconds: number;
|
|
55
57
|
readonly FunctionResponseTypes: readonly SimLambdaFunctionResponseType[];
|
|
58
|
+
readonly FilterCriteria?: SimLambdaFilterCriteriaInput | undefined;
|
|
56
59
|
readonly State: SimLambdaEventSourceMappingState;
|
|
57
60
|
readonly StateTransitionReason: string;
|
|
58
61
|
readonly LastModified: Date;
|
|
@@ -89,6 +92,13 @@ export declare class SimLambdaEventSourceMapping {
|
|
|
89
92
|
*/
|
|
90
93
|
readonly start: SimLambdaEventSourceStart | undefined;
|
|
91
94
|
readonly functionResponseTypes: readonly SimLambdaFunctionResponseType[];
|
|
95
|
+
/**
|
|
96
|
+
* The filters a record has to match before it is delivered, if this mapping
|
|
97
|
+
* was created with any.
|
|
98
|
+
*
|
|
99
|
+
* A mapping with none delivers every record its source hands it.
|
|
100
|
+
*/
|
|
101
|
+
readonly filterCriteria: SimLambdaFilterCriteria | undefined;
|
|
92
102
|
/**
|
|
93
103
|
* When this mapping stops delivering a batch its function keeps failing, for
|
|
94
104
|
* a source that leaves the counting to the mapping.
|
|
@@ -31,6 +31,13 @@ export class SimLambdaEventSourceMapping {
|
|
|
31
31
|
*/
|
|
32
32
|
start;
|
|
33
33
|
functionResponseTypes;
|
|
34
|
+
/**
|
|
35
|
+
* The filters a record has to match before it is delivered, if this mapping
|
|
36
|
+
* was created with any.
|
|
37
|
+
*
|
|
38
|
+
* A mapping with none delivers every record its source hands it.
|
|
39
|
+
*/
|
|
40
|
+
filterCriteria;
|
|
34
41
|
/**
|
|
35
42
|
* When this mapping stops delivering a batch its function keeps failing, for
|
|
36
43
|
* a source that leaves the counting to the mapping.
|
|
@@ -59,6 +66,7 @@ export class SimLambdaEventSourceMapping {
|
|
|
59
66
|
// cannot change what this mapping does with a batch afterwards.
|
|
60
67
|
this.functionResponseTypes = [...(properties.functionResponseTypes ?? [])];
|
|
61
68
|
this.streamRetryLimits = properties.streamRetryLimits;
|
|
69
|
+
this.filterCriteria = properties.filterCriteria;
|
|
62
70
|
this.enabled = properties.enabled ?? true;
|
|
63
71
|
this.lastModified = properties.createdAt;
|
|
64
72
|
}
|
|
@@ -120,6 +128,9 @@ export class SimLambdaEventSourceMapping {
|
|
|
120
128
|
// them out rather than reporting a limit it does not have.
|
|
121
129
|
...this.streamRetryLimits?.configuration(),
|
|
122
130
|
FunctionResponseTypes: this.functionResponseTypes,
|
|
131
|
+
// A mapping created without filters reports none, as real Lambda does,
|
|
132
|
+
// rather than reporting an empty list of them.
|
|
133
|
+
FilterCriteria: this.filterCriteria?.configuration(),
|
|
123
134
|
State: this.#state,
|
|
124
135
|
StateTransitionReason: "USER_INITIATED",
|
|
125
136
|
LastModified: this.lastModified,
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { SimLambdaEventSourceMapping } from "../sim-lambda-event-source-mapping.js";
|
|
2
|
+
import type { SimLambdaStreamHalt } from "./sim-lambda-stream-halt.js";
|
|
3
|
+
/**
|
|
4
|
+
* How many deliveries in a row may feed the source that invoked them before the
|
|
5
|
+
* simulation is refused.
|
|
6
|
+
*
|
|
7
|
+
* One write back is a handler doing its job, and the delivery it causes is the
|
|
8
|
+
* chance for that work to finish. A handler that settles takes two or three
|
|
9
|
+
* links of chain. A handler that loops takes every link there is, and the
|
|
10
|
+
* simulation has to say so before the test times out.
|
|
11
|
+
*/
|
|
12
|
+
export declare const simLambdaStreamCascadeLimit = 10;
|
|
2
13
|
/**
|
|
3
14
|
* The source a guard watches, said in the terms its own service uses.
|
|
4
15
|
*/
|
|
@@ -20,33 +31,49 @@ export interface SimLambdaStreamCascadeSource {
|
|
|
20
31
|
interface SimLambdaStreamCascadeGuardProperties {
|
|
21
32
|
readonly mapping: SimLambdaEventSourceMapping;
|
|
22
33
|
readonly source: SimLambdaStreamCascadeSource;
|
|
34
|
+
/**
|
|
35
|
+
* What a refusal stops, since a mapping polling on from a checkpoint the
|
|
36
|
+
* refusal left where it was would deliver the same records again.
|
|
37
|
+
*/
|
|
38
|
+
readonly halt: SimLambdaStreamHalt;
|
|
23
39
|
}
|
|
24
40
|
/**
|
|
25
|
-
* Watches one mapping's deliveries for the function
|
|
41
|
+
* Watches one mapping's deliveries for a chain of the function feeding the
|
|
26
42
|
* source whose stream invoked it.
|
|
27
43
|
*
|
|
28
44
|
* The delivery runs inside its own asynchronous context, so a record written by
|
|
29
45
|
* the handler is told apart from one written by anything else that happened to
|
|
30
46
|
* be running at the same time. That distinction is the whole point: several
|
|
31
47
|
* records written at once are an ordinary batch, and a handler feeding its own
|
|
32
|
-
* source is a
|
|
48
|
+
* source is the start of a chain.
|
|
49
|
+
*
|
|
50
|
+
* What the guard counts is the chain, and never the shape of one write. A
|
|
51
|
+
* handler that writes back and then finds its own work done writes nothing the
|
|
52
|
+
* second time round, the chain ends at one link, and the simulation settles. A
|
|
53
|
+
* handler that writes back every time takes the chain to
|
|
54
|
+
* `simLambdaStreamCascadeLimit` and is refused there.
|
|
33
55
|
*/
|
|
34
56
|
export declare class SimLambdaStreamCascadeGuard {
|
|
35
57
|
private readonly properties;
|
|
36
|
-
private
|
|
58
|
+
private fedRecords;
|
|
59
|
+
private chained;
|
|
37
60
|
constructor(properties: SimLambdaStreamCascadeGuardProperties);
|
|
38
61
|
/**
|
|
39
|
-
* Run one delivery, refusing afterwards if the
|
|
62
|
+
* Run one delivery, refusing afterwards if the chain has gone on long enough
|
|
63
|
+
* to say the simulation will never settle.
|
|
40
64
|
*
|
|
41
65
|
* The refusal comes after the delivery rather than during it, so the handler
|
|
42
|
-
* sees its own write succeed and the
|
|
66
|
+
* sees its own write succeed and the chain is reported to whoever is waiting
|
|
43
67
|
* for the simulation to settle.
|
|
44
68
|
*/
|
|
45
69
|
around<Result>(delivery: () => Promise<Result>): Promise<Result>;
|
|
46
70
|
/**
|
|
47
|
-
* Note a record written to the polled stream,
|
|
48
|
-
* mapping's own function
|
|
71
|
+
* Note a record written to the polled stream, which counts only while this
|
|
72
|
+
* mapping's own function is the thing that is running.
|
|
73
|
+
*
|
|
74
|
+
* Counted rather than flagged, so a delivery can tell whether the count moved
|
|
75
|
+
* while it ran without the flag having to be put back afterwards.
|
|
49
76
|
*/
|
|
50
|
-
noteRecordWritten():
|
|
77
|
+
noteRecordWritten(): void;
|
|
51
78
|
}
|
|
52
79
|
export {};
|
|
@@ -1,51 +1,74 @@
|
|
|
1
1
|
import { simLambdaEventSourceDeliveryContext } from "./sim-lambda-event-source-delivery-context.js";
|
|
2
2
|
import { SimLambdaStreamCascadeError } from "./sim-lambda-stream-cascade.error.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* How many deliveries in a row may feed the source that invoked them before the
|
|
5
|
+
* simulation is refused.
|
|
6
|
+
*
|
|
7
|
+
* One write back is a handler doing its job, and the delivery it causes is the
|
|
8
|
+
* chance for that work to finish. A handler that settles takes two or three
|
|
9
|
+
* links of chain. A handler that loops takes every link there is, and the
|
|
10
|
+
* simulation has to say so before the test times out.
|
|
11
|
+
*/
|
|
12
|
+
export const simLambdaStreamCascadeLimit = 10;
|
|
13
|
+
/**
|
|
14
|
+
* Watches one mapping's deliveries for a chain of the function feeding the
|
|
5
15
|
* source whose stream invoked it.
|
|
6
16
|
*
|
|
7
17
|
* The delivery runs inside its own asynchronous context, so a record written by
|
|
8
18
|
* the handler is told apart from one written by anything else that happened to
|
|
9
19
|
* be running at the same time. That distinction is the whole point: several
|
|
10
20
|
* records written at once are an ordinary batch, and a handler feeding its own
|
|
11
|
-
* source is a
|
|
21
|
+
* source is the start of a chain.
|
|
22
|
+
*
|
|
23
|
+
* What the guard counts is the chain, and never the shape of one write. A
|
|
24
|
+
* handler that writes back and then finds its own work done writes nothing the
|
|
25
|
+
* second time round, the chain ends at one link, and the simulation settles. A
|
|
26
|
+
* handler that writes back every time takes the chain to
|
|
27
|
+
* `simLambdaStreamCascadeLimit` and is refused there.
|
|
12
28
|
*/
|
|
13
29
|
export class SimLambdaStreamCascadeGuard {
|
|
14
30
|
properties;
|
|
15
|
-
|
|
31
|
+
fedRecords = 0;
|
|
32
|
+
chained = 0;
|
|
16
33
|
constructor(properties) {
|
|
17
34
|
this.properties = properties;
|
|
18
35
|
}
|
|
19
36
|
/**
|
|
20
|
-
* Run one delivery, refusing afterwards if the
|
|
37
|
+
* Run one delivery, refusing afterwards if the chain has gone on long enough
|
|
38
|
+
* to say the simulation will never settle.
|
|
21
39
|
*
|
|
22
40
|
* The refusal comes after the delivery rather than during it, so the handler
|
|
23
|
-
* sees its own write succeed and the
|
|
41
|
+
* sees its own write succeed and the chain is reported to whoever is waiting
|
|
24
42
|
* for the simulation to settle.
|
|
25
43
|
*/
|
|
26
44
|
async around(delivery) {
|
|
45
|
+
const fedBefore = this.fedRecords;
|
|
27
46
|
const result = await simLambdaEventSourceDeliveryContext.run(this, delivery);
|
|
28
|
-
|
|
47
|
+
this.chained = this.fedRecords > fedBefore ? this.chained + 1 : 0;
|
|
48
|
+
if (this.chained >= simLambdaStreamCascadeLimit) {
|
|
29
49
|
const { mapping, source } = this.properties;
|
|
50
|
+
this.properties.halt.stop();
|
|
30
51
|
throw new SimLambdaStreamCascadeError({
|
|
31
52
|
functionName: mapping.functionName,
|
|
32
53
|
streamArn: source.streamArn,
|
|
33
54
|
wroteTo: source.wroteTo,
|
|
34
55
|
sourceRelation: source.sourceRelation,
|
|
35
56
|
advice: source.advice,
|
|
57
|
+
deliveries: this.chained,
|
|
36
58
|
});
|
|
37
59
|
}
|
|
38
60
|
return result;
|
|
39
61
|
}
|
|
40
62
|
/**
|
|
41
|
-
* Note a record written to the polled stream,
|
|
42
|
-
* mapping's own function
|
|
63
|
+
* Note a record written to the polled stream, which counts only while this
|
|
64
|
+
* mapping's own function is the thing that is running.
|
|
65
|
+
*
|
|
66
|
+
* Counted rather than flagged, so a delivery can tell whether the count moved
|
|
67
|
+
* while it ran without the flag having to be put back afterwards.
|
|
43
68
|
*/
|
|
44
69
|
noteRecordWritten() {
|
|
45
|
-
if (
|
|
46
|
-
|
|
70
|
+
if (simLambdaEventSourceDeliveryContext.isDelivering(this)) {
|
|
71
|
+
this.fedRecords += 1;
|
|
47
72
|
}
|
|
48
|
-
this.cascaded = true;
|
|
49
|
-
return true;
|
|
50
73
|
}
|
|
51
74
|
}
|
|
@@ -17,19 +17,28 @@ interface SimLambdaStreamCascadeErrorProperties {
|
|
|
17
17
|
* in a second table, and a Kinesis result belongs on a second stream.
|
|
18
18
|
*/
|
|
19
19
|
readonly advice: string;
|
|
20
|
+
/**
|
|
21
|
+
* How many deliveries in a row fed the source, which is the chain the guard
|
|
22
|
+
* counted before it gave up on the simulation settling.
|
|
23
|
+
*/
|
|
24
|
+
readonly deliveries: number;
|
|
20
25
|
}
|
|
21
26
|
/**
|
|
22
|
-
* A function
|
|
27
|
+
* A function feeding the source whose stream invoked it, delivery after
|
|
28
|
+
* delivery.
|
|
23
29
|
*
|
|
24
30
|
* Every one of those writes is another stream record, which is another
|
|
25
31
|
* delivery, which is another write. Real Lambda runs that loop for as long as
|
|
26
32
|
* the account is willing to pay for it. Nothing here stops on its own, so the
|
|
27
33
|
* simulation would go round until the test timed out with nothing to point at.
|
|
28
34
|
*
|
|
35
|
+
* A handler that writes back and then settles is left alone. This is the chain
|
|
36
|
+
* that carried on, counted by `SimLambdaStreamCascadeGuard` up to
|
|
37
|
+
* `simLambdaStreamCascadeLimit`.
|
|
38
|
+
*
|
|
29
39
|
* This is a simulator guard rather than AWS behaviour, and it is deliberately
|
|
30
|
-
* not silent: a projection or an aggregate belongs in a second
|
|
31
|
-
*
|
|
32
|
-
* loop.
|
|
40
|
+
* not silent: a projection or an aggregate that keeps going belongs in a second
|
|
41
|
+
* table or on a second stream.
|
|
33
42
|
*/
|
|
34
43
|
export declare class SimLambdaStreamCascadeError extends SimLambdaError {
|
|
35
44
|
readonly name = "SimLambdaStreamCascadeError";
|
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
import { SimLambdaError } from "../../error/sim-lambda.error.js";
|
|
2
2
|
/**
|
|
3
|
-
* A function
|
|
3
|
+
* A function feeding the source whose stream invoked it, delivery after
|
|
4
|
+
* delivery.
|
|
4
5
|
*
|
|
5
6
|
* Every one of those writes is another stream record, which is another
|
|
6
7
|
* delivery, which is another write. Real Lambda runs that loop for as long as
|
|
7
8
|
* the account is willing to pay for it. Nothing here stops on its own, so the
|
|
8
9
|
* simulation would go round until the test timed out with nothing to point at.
|
|
9
10
|
*
|
|
11
|
+
* A handler that writes back and then settles is left alone. This is the chain
|
|
12
|
+
* that carried on, counted by `SimLambdaStreamCascadeGuard` up to
|
|
13
|
+
* `simLambdaStreamCascadeLimit`.
|
|
14
|
+
*
|
|
10
15
|
* This is a simulator guard rather than AWS behaviour, and it is deliberately
|
|
11
|
-
* not silent: a projection or an aggregate belongs in a second
|
|
12
|
-
*
|
|
13
|
-
* loop.
|
|
16
|
+
* not silent: a projection or an aggregate that keeps going belongs in a second
|
|
17
|
+
* table or on a second stream.
|
|
14
18
|
*/
|
|
15
19
|
export class SimLambdaStreamCascadeError extends SimLambdaError {
|
|
16
20
|
name = "SimLambdaStreamCascadeError";
|
|
17
21
|
constructor(properties) {
|
|
18
22
|
super(`Function ${properties.functionName} ${properties.wroteTo} while ` +
|
|
19
23
|
`handling records from ${properties.sourceRelation} ` +
|
|
20
|
-
`${properties.streamArn}
|
|
21
|
-
`
|
|
24
|
+
`${properties.streamArn} on ${String(properties.deliveries)} ` +
|
|
25
|
+
`deliveries in a row. Each of those writes was delivered back to the ` +
|
|
26
|
+
`function and brought on the next one, and the simulation is still ` +
|
|
27
|
+
`going round. ${properties.advice}`);
|
|
22
28
|
}
|
|
23
29
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a mapping has finished polling, and the one place that says so.
|
|
3
|
+
*
|
|
4
|
+
* Two things finish a mapping. Deleting it stops the poller, and the cascade
|
|
5
|
+
* guard refusing a chain of the function's own writes stops it too. A poll
|
|
6
|
+
* reads one answer either way, and neither side has to know about the other.
|
|
7
|
+
*/
|
|
8
|
+
export declare class SimLambdaStreamHalt {
|
|
9
|
+
private halted;
|
|
10
|
+
/**
|
|
11
|
+
* Whether polling has finished.
|
|
12
|
+
*/
|
|
13
|
+
get stopped(): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Finish polling.
|
|
16
|
+
*/
|
|
17
|
+
stop(): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a mapping has finished polling, and the one place that says so.
|
|
3
|
+
*
|
|
4
|
+
* Two things finish a mapping. Deleting it stops the poller, and the cascade
|
|
5
|
+
* guard refusing a chain of the function's own writes stops it too. A poll
|
|
6
|
+
* reads one answer either way, and neither side has to know about the other.
|
|
7
|
+
*/
|
|
8
|
+
export class SimLambdaStreamHalt {
|
|
9
|
+
halted = false;
|
|
10
|
+
/**
|
|
11
|
+
* Whether polling has finished.
|
|
12
|
+
*/
|
|
13
|
+
get stopped() {
|
|
14
|
+
return this.halted;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Finish polling.
|
|
18
|
+
*/
|
|
19
|
+
stop() {
|
|
20
|
+
this.halted = true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -14,6 +14,10 @@ interface SimLambdaInvocationDeadlineProperties {
|
|
|
14
14
|
* waits for a handler that has been timed out, and what it goes on to do
|
|
15
15
|
* reaches nobody, which is the closest an in-process simulation gets to an
|
|
16
16
|
* execution environment being taken away.
|
|
17
|
+
*
|
|
18
|
+
* Simulated time standing still holds the handler's timers and the deadline
|
|
19
|
+
* alike. A stall watch on host time ends an invocation neither of them can
|
|
20
|
+
* reach, with an error saying why.
|
|
17
21
|
*/
|
|
18
22
|
export declare class SimLambdaInvocationDeadline {
|
|
19
23
|
#private;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { SimLambdaClockTimer } from "./timer/sim-lambda-clock-timer.js";
|
|
2
2
|
import { SimLambdaInvocationTimers } from "./timer/sim-lambda-invocation-timers.js";
|
|
3
3
|
import { simLambdaProcessTimers } from "./timer/sim-lambda-process-timers.js";
|
|
4
|
+
import { SimLambdaStallWatch } from "./sim-lambda-stall-watch.js";
|
|
5
|
+
import { simLambdaStalledError } from "./sim-lambda-stalled.error.js";
|
|
4
6
|
import { simLambdaTimedOutError } from "./sim-lambda-timed-out.error.js";
|
|
5
7
|
const millisecondsPerSecond = 1000;
|
|
6
8
|
/**
|
|
@@ -13,6 +15,10 @@ const millisecondsPerSecond = 1000;
|
|
|
13
15
|
* waits for a handler that has been timed out, and what it goes on to do
|
|
14
16
|
* reaches nobody, which is the closest an in-process simulation gets to an
|
|
15
17
|
* execution environment being taken away.
|
|
18
|
+
*
|
|
19
|
+
* Simulated time standing still holds the handler's timers and the deadline
|
|
20
|
+
* alike. A stall watch on host time ends an invocation neither of them can
|
|
21
|
+
* reach, with an error saying why.
|
|
16
22
|
*/
|
|
17
23
|
export class SimLambdaInvocationDeadline {
|
|
18
24
|
#properties;
|
|
@@ -40,6 +46,7 @@ export class SimLambdaInvocationDeadline {
|
|
|
40
46
|
const ending = () => {
|
|
41
47
|
timers.cancelAll();
|
|
42
48
|
deadline.cancel();
|
|
49
|
+
stall.cancel();
|
|
43
50
|
};
|
|
44
51
|
const failing = (error) => {
|
|
45
52
|
ending();
|
|
@@ -59,7 +66,21 @@ export class SimLambdaInvocationDeadline {
|
|
|
59
66
|
}));
|
|
60
67
|
},
|
|
61
68
|
});
|
|
69
|
+
const stall = new SimLambdaStallWatch({
|
|
70
|
+
background,
|
|
71
|
+
timeoutSeconds,
|
|
72
|
+
waitingOn: () => timers.pending(),
|
|
73
|
+
stalled: (waitingOn, waitedMilliseconds) => {
|
|
74
|
+
failing(simLambdaStalledError({
|
|
75
|
+
awsRequestId,
|
|
76
|
+
at: background.now(),
|
|
77
|
+
waitingOn,
|
|
78
|
+
waitedMilliseconds,
|
|
79
|
+
}));
|
|
80
|
+
},
|
|
81
|
+
});
|
|
62
82
|
deadline.startAt(new Date(background.now().getTime() + timeoutSeconds * millisecondsPerSecond));
|
|
83
|
+
stall.start();
|
|
63
84
|
try {
|
|
64
85
|
return await background.outstanding(async () => await racing(timers, stopped, handler, ending));
|
|
65
86
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BackgroundScheduler } from "../../../../util/background/background.js";
|
|
2
|
+
import type { SimLambdaPendingTimer } from "./timer/sim-lambda-pending-timer.js";
|
|
3
|
+
interface SimLambdaStallWatchProperties {
|
|
4
|
+
readonly background: BackgroundScheduler;
|
|
5
|
+
/** The seconds the invocation has to answer in, on the simulated clock. */
|
|
6
|
+
readonly timeoutSeconds: number;
|
|
7
|
+
/** The timer the invocation is waiting on, where it is waiting on one. */
|
|
8
|
+
readonly waitingOn: () => SimLambdaPendingTimer | undefined;
|
|
9
|
+
/** What happens once the invocation turns out to have no way to finish. */
|
|
10
|
+
readonly stalled: (waitingOn: SimLambdaPendingTimer, waitedMilliseconds: number) => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A watch on host time for an invocation the simulated clock has left behind.
|
|
14
|
+
*
|
|
15
|
+
* A handler's timers wait on the simulation's clock, and so does the
|
|
16
|
+
* invocation's deadline. Simulated time standing still holds both, and the
|
|
17
|
+
* invocation runs on until the test framework gives up on the test around it.
|
|
18
|
+
* Elapsed host time is the only thing separating that from a test meaning to
|
|
19
|
+
* start an invocation, advance the clock and then wait for it, which is why
|
|
20
|
+
* host time is what this watches.
|
|
21
|
+
*
|
|
22
|
+
* A turn that finds simulated time has moved starts the wait again, so a test
|
|
23
|
+
* advancing the clock in steps is left alone. The host timer is unreferenced,
|
|
24
|
+
* and an invocation nobody is driving never holds the process open.
|
|
25
|
+
*/
|
|
26
|
+
export declare class SimLambdaStallWatch {
|
|
27
|
+
#private;
|
|
28
|
+
constructor(properties: SimLambdaStallWatchProperties);
|
|
29
|
+
/**
|
|
30
|
+
* Start watching, from the instant the clock reads now.
|
|
31
|
+
*/
|
|
32
|
+
start(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Give up watching, as an invocation that has ended does.
|
|
35
|
+
*/
|
|
36
|
+
cancel(): void;
|
|
37
|
+
}
|
|
38
|
+
export {};
|