Skip to content

Commit 1bceb9c

Browse files
ParidelPooyaPooya Paridel
andcommitted
feat(sdk): Add summary generators for map and parallel operations (#91)
*Description of changes:* - Add summaryGenerator field to ConcurrencyConfig interface - Create predefined summary generators for map and parallel operations - Update ConcurrencyController to pass summaryGenerator to top-level runInChildContext only - Update map and parallel handlers to use predefined summary generators - Update tests to expect new configuration fields This enables summaries for large BatchResult payloads in map and parallel operations. *Issue #, if available:* By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. Co-authored-by: Pooya Paridel <parpooya@amazon.com>
1 parent 8f47203 commit 1bceb9c

File tree

11 files changed

+279
-31
lines changed

11 files changed

+279
-31
lines changed

packages/aws-durable-execution-sdk-js/bundle-size-history.json

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,4 @@
11
[
2-
{
3-
"timestamp": "2025-06-27T16:47:20.156Z",
4-
"size": 888765,
5-
"gitCommit": "6c98b2ec2c523a92309a7b8ee00e9c61f83392cf"
6-
},
7-
{
8-
"timestamp": "2025-07-09T20:06:07.839Z",
9-
"size": 891952,
10-
"gitCommit": "bf7ad0b2cbd6aa0a0bf265e67a013bdf1dec4854"
11-
},
122
{
133
"timestamp": "2025-07-10T01:35:30.375Z",
144
"size": 891887,
@@ -248,5 +238,15 @@
248238
"timestamp": "2025-09-29T21:53:05.018Z",
249239
"size": 361581,
250240
"gitCommit": "1eba8c6d9f097275746307697346a5f2caf27c23"
241+
},
242+
{
243+
"timestamp": "2025-10-02T19:08:08.763Z",
244+
"size": 357086,
245+
"gitCommit": "77e3ad5a04f502ab227318b89b47b5ac8b63630f"
246+
},
247+
{
248+
"timestamp": "2025-10-02T19:56:14.710Z",
249+
"size": 357050,
250+
"gitCommit": "7934b1ddf1b32907d5a20f1995a49bfa22845821"
251251
}
252-
]
252+
]

packages/aws-durable-execution-sdk-js/src/handlers/concurrent-execution-handler/concurrent-execution-handler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface ConcurrencyConfig {
1818
maxConcurrency?: number;
1919
topLevelSubType?: string;
2020
iterationSubType?: string;
21+
summaryGenerator?: (result: any) => string;
2122
completionConfig?: {
2223
minSuccessful?: number;
2324
toleratedFailureCount?: number;
@@ -300,6 +301,7 @@ export const createConcurrentExecutionHandler = (
300301

301302
return await runInChildContext(name, executeOperation, {
302303
subType: config?.topLevelSubType,
304+
summaryGenerator: config?.summaryGenerator,
303305
});
304306
};
305307
};

packages/aws-durable-execution-sdk-js/src/handlers/invoke-handler/invoke-handler.test.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,13 @@ describe("InvokeHandler", () => {
268268
});
269269

270270
it("should wait when operation is in progress and other operations are running", async () => {
271-
const mockGetStepData = jest.fn()
271+
const mockGetStepData = jest
272+
.fn()
272273
.mockReturnValueOnce({ Status: OperationStatus.STARTED })
273-
.mockReturnValueOnce({ Status: OperationStatus.SUCCEEDED, InvokeDetails: { Result: '{"result":"success"}' } });
274+
.mockReturnValueOnce({
275+
Status: OperationStatus.SUCCEEDED,
276+
InvokeDetails: { Result: '{"result":"success"}' },
277+
});
274278

275279
mockContext.getStepData = mockGetStepData;
276280
mockHasRunningOperations.mockReturnValue(true); // Other operations running
@@ -303,7 +307,8 @@ describe("InvokeHandler", () => {
303307
});
304308

305309
it("should create checkpoint and terminate for new invoke without name", async () => {
306-
const mockGetStepData = jest.fn()
310+
const mockGetStepData = jest
311+
.fn()
307312
.mockReturnValueOnce(undefined) // First call - no step data
308313
.mockReturnValueOnce({ Status: OperationStatus.STARTED }); // After checkpoint
309314

@@ -358,7 +363,8 @@ describe("InvokeHandler", () => {
358363
});
359364

360365
it("should create checkpoint and terminate for new invoke with name", async () => {
361-
const mockGetStepData = jest.fn()
366+
const mockGetStepData = jest
367+
.fn()
362368
.mockReturnValueOnce(undefined) // First call - no step data
363369
.mockReturnValueOnce({ Status: OperationStatus.STARTED }); // After checkpoint
364370

@@ -397,7 +403,8 @@ describe("InvokeHandler", () => {
397403
});
398404

399405
it("should handle invoke with options", async () => {
400-
const mockGetStepData = jest.fn()
406+
const mockGetStepData = jest
407+
.fn()
401408
.mockReturnValueOnce(undefined) // First call - no step data
402409
.mockReturnValueOnce({ Status: OperationStatus.STARTED }); // After checkpoint
403410

packages/aws-durable-execution-sdk-js/src/handlers/invoke-handler/invoke-handler.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,18 @@ export const createInvokeHandler = (
106106
});
107107
continue; // Re-evaluate status after waiting
108108
}
109-
109+
110110
// No other operations running, safe to terminate
111111
log(
112112
context.isVerbose,
113113
"⏳",
114114
`Invoke ${name || funcId} still in progress, terminating`,
115115
);
116-
return terminate(context, TerminationReason.OPERATION_TERMINATED, stepId);
116+
return terminate(
117+
context,
118+
TerminationReason.OPERATION_TERMINATED,
119+
stepId,
120+
);
117121
}
118122

119123
// Execute with potential interception (testing)

packages/aws-durable-execution-sdk-js/src/handlers/map-handler/map-handler.test.ts

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,15 @@ describe("Map Handler", () => {
4747
{ id: "map-item-1", data: "item2", index: 1 },
4848
],
4949
expect.any(Function),
50-
TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
50+
{
51+
...{
52+
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
53+
summaryGenerator: expect.any(Function),
54+
completionConfig: undefined,
55+
},
56+
summaryGenerator: expect.any(Function),
57+
completionConfig: undefined,
58+
},
5159
);
5260
});
5361

@@ -70,7 +78,11 @@ describe("Map Handler", () => {
7078
{ id: "map-item-1", data: "item2", index: 1 },
7179
],
7280
expect.any(Function),
73-
TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
81+
{
82+
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
83+
summaryGenerator: expect.any(Function),
84+
completionConfig: undefined,
85+
},
7486
);
7587
});
7688

@@ -89,15 +101,23 @@ describe("Map Handler", () => {
89101
undefined,
90102
[{ id: "map-item-0", data: "item", index: 0 }],
91103
expect.any(Function),
92-
TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
104+
{
105+
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
106+
summaryGenerator: expect.any(Function),
107+
completionConfig: undefined,
108+
},
93109
);
94110
});
95111

96112
it("should parse parameters with config", async () => {
97113
const items = ["item1", "item2"];
98114
const mapFunc: MapFunc<string> = jest.fn().mockResolvedValue("result");
99115
const config = {
100-
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
116+
...{
117+
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
118+
summaryGenerator: expect.any(Function),
119+
completionConfig: undefined,
120+
},
101121
maxConcurrency: 2,
102122
};
103123

@@ -116,7 +136,14 @@ describe("Map Handler", () => {
116136
{ id: "map-item-1", data: "item2", index: 1 },
117137
],
118138
expect.any(Function),
119-
{ ...TEST_CONSTANTS.DEFAULT_MAP_CONFIG, maxConcurrency: 2 },
139+
{
140+
...{
141+
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
142+
summaryGenerator: expect.any(Function),
143+
completionConfig: undefined,
144+
},
145+
maxConcurrency: 2,
146+
},
120147
);
121148
});
122149
});
@@ -154,7 +181,11 @@ describe("Map Handler", () => {
154181
undefined,
155182
[],
156183
expect.any(Function),
157-
TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
184+
{
185+
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
186+
summaryGenerator: expect.any(Function),
187+
completionConfig: undefined,
188+
},
158189
);
159190
});
160191

@@ -179,7 +210,11 @@ describe("Map Handler", () => {
179210
{ id: "map-item-2", data: "item3", index: 2 },
180211
],
181212
expect.any(Function),
182-
TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
213+
{
214+
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
215+
summaryGenerator: expect.any(Function),
216+
completionConfig: undefined,
217+
},
183218
);
184219
});
185220

@@ -251,7 +286,11 @@ describe("Map Handler", () => {
251286
const items = ["item1", "item2"];
252287
const mapFunc: MapFunc<string> = jest.fn().mockResolvedValue("result");
253288
const config = {
254-
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
289+
...{
290+
...TEST_CONSTANTS.DEFAULT_MAP_CONFIG,
291+
summaryGenerator: expect.any(Function),
292+
completionConfig: undefined,
293+
},
255294
maxConcurrency: 5,
256295
};
257296

packages/aws-durable-execution-sdk-js/src/handlers/map-handler/map-handler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
} from "../../types";
1010
import { log } from "../../utils/logger/logger";
1111
import { BatchResult } from "../concurrent-execution-handler/batch-result";
12+
import { createMapSummaryGenerator } from "../../utils/summary-generators";
1213

1314
export const createMapHandler = (
1415
context: ExecutionContext,
@@ -74,6 +75,7 @@ export const createMapHandler = (
7475
maxConcurrency: config?.maxConcurrency,
7576
topLevelSubType: OperationSubType.MAP,
7677
iterationSubType: OperationSubType.MAP_ITERATION,
78+
summaryGenerator: createMapSummaryGenerator(),
7779
completionConfig: config?.completionConfig,
7880
});
7981

packages/aws-durable-execution-sdk-js/src/handlers/parallel-handler/parallel-handler.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ describe("Parallel Handler", () => {
6363
completionConfig: undefined,
6464
iterationSubType: "ParallelBranch",
6565
maxConcurrency: undefined,
66+
summaryGenerator: expect.any(Function),
6667
topLevelSubType: "Parallel",
6768
},
6869
);
@@ -91,6 +92,7 @@ describe("Parallel Handler", () => {
9192
completionConfig: undefined,
9293
iterationSubType: "ParallelBranch",
9394
maxConcurrency: 2,
95+
summaryGenerator: expect.any(Function),
9496
topLevelSubType: "Parallel",
9597
},
9698
);
@@ -119,6 +121,7 @@ describe("Parallel Handler", () => {
119121
completionConfig: undefined,
120122
iterationSubType: "ParallelBranch",
121123
maxConcurrency: 3,
124+
summaryGenerator: expect.any(Function),
122125
topLevelSubType: "Parallel",
123126
},
124127
);

packages/aws-durable-execution-sdk-js/src/handlers/parallel-handler/parallel-handler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
} from "../../types";
1010
import { log } from "../../utils/logger/logger";
1111
import { BatchResult } from "../concurrent-execution-handler/batch-result";
12+
import { createParallelSummaryGenerator } from "../../utils/summary-generators";
1213

1314
export const createParallelHandler = (
1415
context: ExecutionContext,
@@ -84,6 +85,7 @@ export const createParallelHandler = (
8485
maxConcurrency: config?.maxConcurrency,
8586
topLevelSubType: OperationSubType.PARALLEL,
8687
iterationSubType: OperationSubType.PARALLEL_BRANCH,
88+
summaryGenerator: createParallelSummaryGenerator(),
8789
completionConfig: config?.completionConfig,
8890
});
8991

0 commit comments

Comments
 (0)