Skip to content

Commit 9881d2f

Browse files
committed
Change operation IDs to hashed values
1 parent ffdf0db commit 9881d2f

5 files changed

Lines changed: 42 additions & 47 deletions

File tree

sdk/src/main/java/software/amazon/lambda/durable/DurableContext.java

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33
package software.amazon.lambda.durable;
44

5+
import com.amazonaws.services.lambda.runtime.Context;
56
import java.nio.charset.StandardCharsets;
67
import java.security.MessageDigest;
78
import java.security.NoSuchAlgorithmException;
@@ -11,11 +12,7 @@
1112
import java.util.concurrent.atomic.AtomicInteger;
1213
import java.util.function.Function;
1314
import java.util.function.Supplier;
14-
1515
import org.slf4j.LoggerFactory;
16-
17-
import com.amazonaws.services.lambda.runtime.Context;
18-
1916
import software.amazon.lambda.durable.execution.ExecutionManager;
2017
import software.amazon.lambda.durable.logging.DurableLogger;
2118
import software.amazon.lambda.durable.operation.CallbackOperation;
@@ -316,22 +313,20 @@ public DurableLogger getLogger() {
316313
}
317314

318315
/**
319-
* Get the next operationId.
320-
* Returns a globally unique operation ID by hashing a sequential operation counter.
321-
* For root contexts, the counter value is hashed directly (e.g. "1", "2", "3").
322-
* For child contexts, the values are prefixed with the parent hashed contextId
323-
* (e.g. "<hash>-1", "<hash>-2" inside parent context <hash>).
324-
* This matches the JavaScript SDK's stepPrefix convention and prevents ID collisions in checkpoint batches.
316+
* Get the next operationId. Returns a globally unique operation ID by hashing a sequential operation counter. For
317+
* root contexts, the counter value is hashed directly (e.g. "1", "2", "3"). For child contexts, the values are
318+
* prefixed with the parent hashed contextId (e.g. "<hash>-1", "<hash>-2" inside parent context <hash>). This
319+
* matches the JavaScript SDK's stepPrefix convention and prevents ID collisions in checkpoint batches.
325320
*/
326321
private String nextOperationId() {
327322
var counter = String.valueOf(operationCounter.incrementAndGet());
328-
var rawId = getContextId() != null ? getContextId() + "-" + counter : counter;
329-
try {
330-
var messageDigest = MessageDigest.getInstance("SHA-256");
331-
var hash = messageDigest.digest(rawId.getBytes(StandardCharsets.UTF_8));
332-
return HexFormat.of().formatHex(hash);
333-
} catch (NoSuchAlgorithmException e) {
334-
throw new RuntimeException("failed to get next operation id, SHA-256 not available", e);
335-
}
323+
var rawId = getContextId() != null ? getContextId() + "-" + counter : counter;
324+
try {
325+
var messageDigest = MessageDigest.getInstance("SHA-256");
326+
var hash = messageDigest.digest(rawId.getBytes(StandardCharsets.UTF_8));
327+
return HexFormat.of().formatHex(hash);
328+
} catch (NoSuchAlgorithmException e) {
329+
throw new RuntimeException("failed to get next operation id, SHA-256 not available", e);
330+
}
336331
}
337332
}

sdk/src/test/java/software/amazon/lambda/durable/DurableContextTest.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33
package software.amazon.lambda.durable;
4+
45
import static org.junit.jupiter.api.Assertions.*;
6+
57
import java.time.Duration;
68
import java.util.ArrayList;
79
import java.util.List;
8-
910
import org.junit.jupiter.api.Test;
10-
1111
import software.amazon.awssdk.services.lambda.model.*;
1212
import software.amazon.lambda.durable.execution.ExecutionManager;
1313
import software.amazon.lambda.durable.execution.SuspendExecutionException;
@@ -131,8 +131,10 @@ void testWait() {
131131
@Test
132132
void testWaitReplay() {
133133
// Create context with completed wait operation
134-
var existingOp =
135-
Operation.builder().id(TestUtils.hashOperationId("1")).status(OperationStatus.SUCCEEDED).build();
134+
var existingOp = Operation.builder()
135+
.id(TestUtils.hashOperationId("1"))
136+
.status(OperationStatus.SUCCEEDED)
137+
.build();
136138
var context = createTestContext(List.of(existingOp));
137139

138140
// Wait should complete immediately (no exception)
@@ -177,8 +179,10 @@ void testCombinedReplay() throws Exception {
177179
.status(OperationStatus.SUCCEEDED)
178180
.stepDetails(StepDetails.builder().result("100").build())
179181
.build();
180-
var waitOp =
181-
Operation.builder().id(TestUtils.hashOperationId("3")).status(OperationStatus.SUCCEEDED).build();
182+
var waitOp = Operation.builder()
183+
.id(TestUtils.hashOperationId("3"))
184+
.status(OperationStatus.SUCCEEDED)
185+
.build();
182186
var context = createTestContext(List.of(syncOp, asyncOp, waitOp));
183187

184188
// All operations should replay from cache

sdk/src/test/java/software/amazon/lambda/durable/DurableExecutionTest.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22
// SPDX-License-Identifier: Apache-2.0
33
package software.amazon.lambda.durable;
44

5-
import java.util.List;
6-
import java.util.concurrent.ExecutorService;
7-
85
import static org.junit.jupiter.api.Assertions.assertEquals;
96
import static org.junit.jupiter.api.Assertions.assertFalse;
107
import static org.junit.jupiter.api.Assertions.assertNotNull;
118
import static org.junit.jupiter.api.Assertions.assertNull;
129
import static org.junit.jupiter.api.Assertions.assertThrows;
1310
import static org.junit.jupiter.api.Assertions.assertTrue;
14-
import org.junit.jupiter.api.Test;
1511

12+
import java.util.List;
13+
import java.util.concurrent.ExecutorService;
14+
import org.junit.jupiter.api.Test;
1615
import software.amazon.awssdk.services.lambda.model.CheckpointUpdatedExecutionState;
1716
import software.amazon.awssdk.services.lambda.model.ExecutionDetails;
1817
import software.amazon.awssdk.services.lambda.model.Operation;

sdk/src/test/java/software/amazon/lambda/durable/ReplayValidationTest.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22
// SPDX-License-Identifier: Apache-2.0
33
package software.amazon.lambda.durable;
44

5-
import java.time.Duration;
6-
import java.util.List;
7-
import java.util.stream.Stream;
8-
95
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
106
import static org.junit.jupiter.api.Assertions.assertThrows;
117
import static org.junit.jupiter.api.Assertions.assertTrue;
12-
import org.junit.jupiter.api.Test;
138

9+
import java.time.Duration;
10+
import java.util.List;
11+
import java.util.stream.Stream;
12+
import org.junit.jupiter.api.Test;
1413
import software.amazon.awssdk.services.lambda.model.CheckpointUpdatedExecutionState;
1514
import software.amazon.awssdk.services.lambda.model.Operation;
1615
import software.amazon.awssdk.services.lambda.model.OperationStatus;

sdk/src/test/java/software/amazon/lambda/durable/TestUtils.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,16 @@
22
// SPDX-License-Identifier: Apache-2.0
33
package software.amazon.lambda.durable;
44

5-
import java.nio.charset.StandardCharsets;
6-
import java.security.MessageDigest;
7-
import java.security.NoSuchAlgorithmException;
8-
95
import static org.mockito.ArgumentMatchers.*;
106
import static org.mockito.Mockito.*;
117

8+
import java.nio.charset.StandardCharsets;
9+
import java.security.MessageDigest;
10+
import java.security.NoSuchAlgorithmException;
1211
import java.util.ArrayList;
1312
import java.util.HexFormat;
1413
import java.util.List;
1514
import java.util.UUID;
16-
1715
import software.amazon.awssdk.services.lambda.model.*;
1816
import software.amazon.lambda.durable.client.DurableExecutionClient;
1917

@@ -68,13 +66,13 @@ public static DurableExecutionClient createMockClient() {
6866
return client;
6967
}
7068

71-
public static String hashOperationId(String rawId) {
72-
try {
73-
var messageDigest = MessageDigest.getInstance("SHA-256");
74-
var hash = messageDigest.digest(rawId.getBytes(StandardCharsets.UTF_8));
75-
return HexFormat.of().formatHex(hash);
76-
} catch (NoSuchAlgorithmException e) {
77-
throw new AssertionError("SHA-256 not available", e);
78-
}
79-
}
69+
public static String hashOperationId(String rawId) {
70+
try {
71+
var messageDigest = MessageDigest.getInstance("SHA-256");
72+
var hash = messageDigest.digest(rawId.getBytes(StandardCharsets.UTF_8));
73+
return HexFormat.of().formatHex(hash);
74+
} catch (NoSuchAlgorithmException e) {
75+
throw new AssertionError("SHA-256 not available", e);
76+
}
77+
}
8078
}

0 commit comments

Comments
 (0)