Skip to content

Commit 150df44

Browse files
authored
feat(sdk): add executionContext.durableExecutionArn to context object (#430)
Introduces a new `executionCotext` property to the `DurableContext` interface that provides readonly access to execution metadata including `durableExecutionArn`. This approach consolidates all readonly execution properties under a single namespace rather than adding individual fields directly to the context interface, maintaining a cleaner API surface.
1 parent 64fc875 commit 150df44

File tree

3 files changed

+106
-27
lines changed

3 files changed

+106
-27
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { DurableContextImpl } from "./durable-context";
2+
import { ExecutionContext, DurableExecutionMode } from "../../types/core";
3+
import { Context } from "aws-lambda";
4+
5+
describe("DurableContext executionContext property", () => {
6+
it("should expose durableExecutionArn in executionContext property", () => {
7+
const DurableExecutionArn =
8+
"arn:aws:lambda:us-east-1:123456789012:function:f1:$LATEST/durable-execution/execution-name";
9+
10+
const mockExecutionContext: ExecutionContext = {
11+
durableExecutionArn: DurableExecutionArn,
12+
durableExecutionClient: {} as any,
13+
_stepData: {},
14+
terminationManager: {} as any,
15+
requestId: "test-request-id",
16+
tenantId: undefined,
17+
pendingCompletions: new Set(),
18+
getStepData: jest.fn(),
19+
};
20+
21+
const mockLambdaContext: Context = {
22+
callbackWaitsForEmptyEventLoop: false,
23+
functionName: "test-function",
24+
functionVersion: "1",
25+
invokedFunctionArn:
26+
"arn:aws:lambda:us-east-1:123456789012:function:test-function:1",
27+
memoryLimitInMB: "128",
28+
awsRequestId: "test-request-id",
29+
logGroupName: "/aws/lambda/test-function",
30+
logStreamName: "2024/01/01/[$LATEST]abcdef123456",
31+
getRemainingTimeInMillis: () => 30000,
32+
done: jest.fn(),
33+
fail: jest.fn(),
34+
succeed: jest.fn(),
35+
};
36+
37+
const mockLogger = {
38+
info: jest.fn(),
39+
error: jest.fn(),
40+
warn: jest.fn(),
41+
debug: jest.fn(),
42+
};
43+
44+
const mockDurableExecution = {
45+
checkpointManager: {} as any,
46+
};
47+
48+
const context = new DurableContextImpl(
49+
mockExecutionContext,
50+
mockLambdaContext,
51+
DurableExecutionMode.ExecutionMode,
52+
mockLogger as any,
53+
undefined,
54+
mockDurableExecution as any,
55+
);
56+
57+
expect(context.executionContext).toBeDefined();
58+
expect(context.executionContext.durableExecutionArn).toBe(
59+
DurableExecutionArn,
60+
);
61+
});
62+
});

packages/aws-durable-execution-sdk-js/src/context/durable-context/durable-context.ts

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,12 @@ export class DurableContextImpl<Logger extends DurableLogger>
7474
private durableExecution: DurableExecution;
7575

7676
public logger: DurableContextLogger<Logger>;
77+
public readonly executionContext: {
78+
readonly durableExecutionArn: string;
79+
};
7780

7881
constructor(
79-
private executionContext: ExecutionContext,
82+
private _executionContext: ExecutionContext,
8083
public lambdaContext: Context,
8184
durableExecutionMode: DurableExecutionMode,
8285
inheritedLogger: Logger,
@@ -93,6 +96,10 @@ export class DurableContextImpl<Logger extends DurableLogger>
9396
);
9497
this.logger = this.createModeAwareLogger(inheritedLogger);
9598

99+
this.executionContext = {
100+
durableExecutionArn: _executionContext.durableExecutionArn,
101+
};
102+
96103
this.durableExecutionMode = durableExecutionMode;
97104

98105
this.checkpoint = durableExecution.checkpointManager;
@@ -114,9 +121,9 @@ export class DurableContextImpl<Logger extends DurableLogger>
114121
const activeContext = getActiveContext();
115122

116123
const result: DurableLogData = {
117-
executionArn: this.executionContext.durableExecutionArn,
118-
requestId: this.executionContext.requestId,
119-
tenantId: this.executionContext.tenantId,
124+
executionArn: this._executionContext.durableExecutionArn,
125+
requestId: this._executionContext.requestId,
126+
tenantId: this._executionContext.tenantId,
120127
operationId:
121128
!activeContext || activeContext?.contextId === "root"
122129
? undefined
@@ -209,7 +216,7 @@ export class DurableContextImpl<Logger extends DurableLogger>
209216
private checkAndUpdateReplayMode(): void {
210217
if (this.durableExecutionMode === DurableExecutionMode.ReplayMode) {
211218
const nextStepId = this.getNextStepId();
212-
const nextStepData = this.executionContext.getStepData(nextStepId);
219+
const nextStepData = this._executionContext.getStepData(nextStepId);
213220
if (!nextStepData) {
214221
this.durableExecutionMode = DurableExecutionMode.ExecutionMode;
215222
}
@@ -220,7 +227,7 @@ export class DurableContextImpl<Logger extends DurableLogger>
220227
const wasInReplayMode =
221228
this.durableExecutionMode === DurableExecutionMode.ReplayMode;
222229
const nextStepId = this.getNextStepId();
223-
const stepData = this.executionContext.getStepData(nextStepId);
230+
const stepData = this._executionContext.getStepData(nextStepId);
224231
const wasNotFinished = !!(
225232
stepData &&
226233
stepData.Status !== OperationStatus.SUCCEEDED &&
@@ -234,7 +241,7 @@ export class DurableContextImpl<Logger extends DurableLogger>
234241
this.durableExecutionMode === DurableExecutionMode.ReplaySucceededContext
235242
) {
236243
const nextStepId = this.getNextStepId();
237-
const nextStepData = this.executionContext.getStepData(nextStepId);
244+
const nextStepData = this._executionContext.getStepData(nextStepId);
238245
if (
239246
nextStepData &&
240247
nextStepData.Status !== OperationStatus.SUCCEEDED &&
@@ -264,12 +271,12 @@ export class DurableContextImpl<Logger extends DurableLogger>
264271
validateContextUsage(
265272
this._stepPrefix,
266273
"step",
267-
this.executionContext.terminationManager,
274+
this._executionContext.terminationManager,
268275
);
269276

270277
return this.withDurableModeManagement(() => {
271278
const stepHandler = createStepHandler(
272-
this.executionContext,
279+
this._executionContext,
273280
this.checkpoint,
274281
this.lambdaContext,
275282
this.createStepId.bind(this),
@@ -290,11 +297,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
290297
validateContextUsage(
291298
this._stepPrefix,
292299
"invoke",
293-
this.executionContext.terminationManager,
300+
this._executionContext.terminationManager,
294301
);
295302
return this.withDurableModeManagement(() => {
296303
const invokeHandler = createInvokeHandler(
297-
this.executionContext,
304+
this._executionContext,
298305
this.checkpoint,
299306
this.createStepId.bind(this),
300307
this._parentId,
@@ -319,11 +326,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
319326
validateContextUsage(
320327
this._stepPrefix,
321328
"runInChildContext",
322-
this.executionContext.terminationManager,
329+
this._executionContext.terminationManager,
323330
);
324331
return this.withDurableModeManagement(() => {
325332
const blockHandler = createRunInChildContextHandler(
326-
this.executionContext,
333+
this._executionContext,
327334
this.checkpoint,
328335
this.lambdaContext,
329336
this.createStepId.bind(this),
@@ -360,11 +367,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
360367
validateContextUsage(
361368
this._stepPrefix,
362369
"wait",
363-
this.executionContext.terminationManager,
370+
this._executionContext.terminationManager,
364371
);
365372
return this.withDurableModeManagement(() => {
366373
const waitHandler = createWaitHandler(
367-
this.executionContext,
374+
this._executionContext,
368375
this.checkpoint,
369376
this.createStepId.bind(this),
370377
this._parentId,
@@ -411,11 +418,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
411418
validateContextUsage(
412419
this._stepPrefix,
413420
"createCallback",
414-
this.executionContext.terminationManager,
421+
this._executionContext.terminationManager,
415422
);
416423
return this.withDurableModeManagement(() => {
417424
const callbackFactory = createCallbackFactory(
418-
this.executionContext,
425+
this._executionContext,
419426
this.checkpoint,
420427
this.createStepId.bind(this),
421428
this.checkAndUpdateReplayMode.bind(this),
@@ -435,11 +442,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
435442
validateContextUsage(
436443
this._stepPrefix,
437444
"waitForCallback",
438-
this.executionContext.terminationManager,
445+
this._executionContext.terminationManager,
439446
);
440447
return this.withDurableModeManagement(() => {
441448
const waitForCallbackHandler = createWaitForCallbackHandler(
442-
this.executionContext,
449+
this._executionContext,
443450
this.getNextStepId.bind(this),
444451
this.runInChildContext.bind(this),
445452
);
@@ -461,11 +468,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
461468
validateContextUsage(
462469
this._stepPrefix,
463470
"waitForCondition",
464-
this.executionContext.terminationManager,
471+
this._executionContext.terminationManager,
465472
);
466473
return this.withDurableModeManagement(() => {
467474
const waitForConditionHandler = createWaitForConditionHandler(
468-
this.executionContext,
475+
this._executionContext,
469476
this.checkpoint,
470477
this.createStepId.bind(this),
471478
this.durableLogger,
@@ -497,11 +504,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
497504
validateContextUsage(
498505
this._stepPrefix,
499506
"map",
500-
this.executionContext.terminationManager,
507+
this._executionContext.terminationManager,
501508
);
502509
return this.withDurableModeManagement(() => {
503510
const mapHandler = createMapHandler(
504-
this.executionContext,
511+
this._executionContext,
505512
this._executeConcurrently.bind(this),
506513
);
507514
return mapHandler(
@@ -526,11 +533,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
526533
validateContextUsage(
527534
this._stepPrefix,
528535
"parallel",
529-
this.executionContext.terminationManager,
536+
this._executionContext.terminationManager,
530537
);
531538
return this.withDurableModeManagement(() => {
532539
const parallelHandler = createParallelHandler(
533-
this.executionContext,
540+
this._executionContext,
534541
this._executeConcurrently.bind(this),
535542
);
536543
return parallelHandler(nameOrBranches, branchesOrConfig, maybeConfig);
@@ -550,11 +557,11 @@ export class DurableContextImpl<Logger extends DurableLogger>
550557
validateContextUsage(
551558
this._stepPrefix,
552559
"_executeConcurrently",
553-
this.executionContext.terminationManager,
560+
this._executionContext.terminationManager,
554561
);
555562
return this.withDurableModeManagement(() => {
556563
const concurrentExecutionHandler = createConcurrentExecutionHandler(
557-
this.executionContext,
564+
this._executionContext,
558565
this.runInChildContext.bind(this),
559566
this.skipNextOperation.bind(this),
560567
);

packages/aws-durable-execution-sdk-js/src/types/durable-context.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,16 @@ export interface DurableContext<TLogger extends DurableLogger = DurableLogger> {
6565
*/
6666
logger: DurableContextLogger<TLogger>;
6767

68+
/**
69+
* Readonly metadata about the current execution context
70+
*/
71+
executionContext: {
72+
/**
73+
* The ARN of the current durable execution
74+
*/
75+
readonly durableExecutionArn: string;
76+
};
77+
6878
/**
6979
* Executes a function as a durable step with automatic retry and state persistence
7080
*

0 commit comments

Comments
 (0)