Skip to content

Commit 9c52a98

Browse files
committed
refactor(claimcheck): rename s3offload sample to claimcheck
Signed-off-by: “Kevin” <kevlar_ksb@yahoo.com>
1 parent 230dd3f commit 9c52a98

10 files changed

Lines changed: 211 additions & 201 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ These samples demonstrate various capabilities of Java Cadence client and server
3232
* **DataConverter Samples** — three independent custom `DataConverter` patterns that transparently transform every workflow input, output, and activity parameter. Each lives in its own package and is fully standalone, so you can copy any one of them into your own project:
3333
* **Compression** ([`com.uber.cadence.samples.compression`](src/main/java/com/uber/cadence/samples/compression/)) — gzip-over-JSON; typically 60-80% size reduction for repetitive payloads. [README](src/main/java/com/uber/cadence/samples/compression/README.md).
3434
* **Encryption** ([`com.uber.cadence.samples.encryption`](src/main/java/com/uber/cadence/samples/encryption/)) — AES-256-GCM so payloads in Cadence history are unreadable without the key. [README](src/main/java/com/uber/cadence/samples/encryption/README.md).
35-
* **S3 / claim-check offload** ([`com.uber.cadence.samples.s3offload`](src/main/java/com/uber/cadence/samples/s3offload/)) — payloads above a threshold are stored in an external `BlobStore`; only a small reference travels through history. [README](src/main/java/com/uber/cadence/samples/s3offload/README.md).
35+
* **Claim-check offload** ([`com.uber.cadence.samples.claimcheck`](src/main/java/com/uber/cadence/samples/claimcheck/)) — payloads above a threshold are stored in an external `BlobStore` (S3, GCS, Azure Blob, MinIO, local disk); only a small reference travels through history. [README](src/main/java/com/uber/cadence/samples/claimcheck/README.md).
3636

3737
## Get the Samples
3838

@@ -162,12 +162,12 @@ See [src/main/java/com/uber/cadence/samples/encryption/README.md](src/main/java/
162162
./gradlew -q execute -PmainClass=com.uber.cadence.samples.encryption.EncryptionWorker
163163
./gradlew -q execute -PmainClass=com.uber.cadence.samples.encryption.EncryptionStarter
164164

165-
#### S3 / claim-check offload
165+
#### Claim-check offload
166166

167-
See [src/main/java/com/uber/cadence/samples/s3offload/README.md](src/main/java/com/uber/cadence/samples/s3offload/README.md) for the AWS SDK swap-in instructions.
167+
See [src/main/java/com/uber/cadence/samples/claimcheck/README.md](src/main/java/com/uber/cadence/samples/claimcheck/README.md) for swap-in instructions for S3, GCS, Azure Blob, and MinIO.
168168

169-
./gradlew -q execute -PmainClass=com.uber.cadence.samples.s3offload.S3OffloadWorker
170-
./gradlew -q execute -PmainClass=com.uber.cadence.samples.s3offload.S3OffloadStarter
169+
./gradlew -q execute -PmainClass=com.uber.cadence.samples.claimcheck.ClaimCheckWorker
170+
./gradlew -q execute -PmainClass=com.uber.cadence.samples.claimcheck.ClaimCheckStarter
171171

172172
### Trip Booking
173173

src/main/java/com/uber/cadence/samples/s3offload/BlobStore.java renamed to src/main/java/com/uber/cadence/samples/claimcheck/BlobStore.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
* permissions and limitations under the License.
1616
*/
1717

18-
package com.uber.cadence.samples.s3offload;
18+
package com.uber.cadence.samples.claimcheck;
1919

2020
import java.io.IOException;
2121

2222
/**
23-
* Abstraction over any external object store (local filesystem, S3, GCS, etc.).
23+
* Abstraction over any external object store (local filesystem, S3, GCS, Azure Blob, etc.).
2424
*
25-
* <p>{@link S3OffloadDataConverter} uses this interface to store large payloads outside Cadence
25+
* <p>{@link ClaimCheckDataConverter} uses this interface to store large payloads outside Cadence
2626
* history. The default implementation is {@link LocalFsBlobStore}, which writes to the system
2727
* temporary directory and requires no external services.
2828
*/

src/main/java/com/uber/cadence/samples/s3offload/S3OffloadDataConverter.java renamed to src/main/java/com/uber/cadence/samples/claimcheck/ClaimCheckDataConverter.java

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* permissions and limitations under the License.
1616
*/
1717

18-
package com.uber.cadence.samples.s3offload;
18+
package com.uber.cadence.samples.claimcheck;
1919

2020
import com.uber.cadence.converter.DataConverter;
2121
import com.uber.cadence.converter.DataConverterException;
@@ -39,7 +39,7 @@
3939
* <ul>
4040
* <li>{@code 0x00 || json} — payload is small enough to inline.
4141
* <li>{@code 0x01 || jsonEnvelope} — payload was offloaded; the envelope JSON has the form {@code
42-
* {"s3Ref":"<bucket>/<sha256hex>"}}.
42+
* {"blobRef":"<bucket>/<sha256hex>"}}.
4343
* </ul>
4444
*
4545
* <p>Keys are derived from the SHA-256 of the payload so {@code toData} is idempotent across
@@ -50,12 +50,19 @@
5050
*/
5151
/*
5252
* =============================================================================
53-
* S3 BlobStore stub
53+
* Swapping LocalFsBlobStore for a real object store
5454
*
55-
* To use a real AWS S3 bucket instead of the local filesystem:
56-
* 1. Add AWS SDK v2 to build.gradle:
57-
* implementation group: 'software.amazon.awssdk', name: 's3', version: '2.25.0'
58-
* 2. Implement BlobStore against software.amazon.awssdk.services.s3.S3Client:
55+
* The DataConverter is storage-agnostic: any class that implements `BlobStore` (two methods, `put`
56+
* and `get`) will work. Swap `new LocalFsBlobStore()` in ClaimCheckWorker for your own impl and the
57+
* workflow/activity code stays the same. Backend pointers:
58+
*
59+
* - AWS S3: software.amazon.awssdk:s3:2.25.0 (S3Client + PutObjectRequest/GetObjectRequest)
60+
* - GCS: com.google.cloud:google-cloud-storage (Storage.create(blobInfo, bytes))
61+
* - Azure Blob: com.azure:azure-storage-blob (BlobContainerClient.getBlobClient(...))
62+
* - MinIO / R2 /
63+
* LocalStack: same as S3, just call S3Client.builder().endpointOverride(URI.create("..."))
64+
*
65+
* Reference S3 sketch using AWS SDK v2:
5966
*
6067
* public final class S3BlobStore implements BlobStore {
6168
* private final S3Client s3;
@@ -78,18 +85,18 @@
7885
* }
7986
* }
8087
*
81-
* 3. Replace `new LocalFsBlobStore()` with `new S3BlobStore("my-bucket", "us-east-1")` in
82-
* S3OffloadWorker.
83-
* 4. Set standard AWS env vars (AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) or use an
84-
* IAM instance role.
85-
*
86-
* You can also point the SDK at LocalStack or MinIO for local testing without a real AWS account.
88+
* Wiring steps for any backend:
89+
* 1. Add the backend's SDK as a runtime dependency in build.gradle.
90+
* 2. Implement BlobStore against that SDK (≈30 lines, like the sketch above).
91+
* 3. Replace `new LocalFsBlobStore()` with your `BlobStore` impl in ClaimCheckWorker.
92+
* 4. Provide credentials via the SDK's standard mechanism (env vars, IAM role, etc.).
8793
*
8894
* Note on cleanup: this DataConverter does not delete blobs after the workflow completes. In
89-
* production, use S3 object lifecycle policies to automatically expire old blobs.
95+
* production, use the object store's lifecycle policies (S3 object lifecycle, GCS object lifecycle
96+
* management, Azure Blob lifecycle management, etc.) to automatically expire old blobs.
9097
* =============================================================================
9198
*/
92-
public final class S3OffloadDataConverter implements DataConverter {
99+
public final class ClaimCheckDataConverter implements DataConverter {
93100

94101
/** Prefix byte for inline (below-threshold) payloads. */
95102
static final byte INLINE_PREFIX = (byte) 0x00;
@@ -104,12 +111,12 @@ public final class S3OffloadDataConverter implements DataConverter {
104111
private final int thresholdBytes;
105112

106113
static final class BlobReference {
107-
public String s3Ref;
114+
public String blobRef;
108115

109116
public BlobReference() {}
110117

111-
BlobReference(String s3Ref) {
112-
this.s3Ref = s3Ref;
118+
BlobReference(String blobRef) {
119+
this.blobRef = blobRef;
113120
}
114121
}
115122

@@ -118,7 +125,7 @@ public BlobReference() {}
118125
* @param bucket logical bucket / prefix name embedded in the reference key.
119126
* @param thresholdBytes max inline payload size; larger payloads are offloaded.
120127
*/
121-
public S3OffloadDataConverter(BlobStore store, String bucket, int thresholdBytes) {
128+
public ClaimCheckDataConverter(BlobStore store, String bucket, int thresholdBytes) {
122129
if (store == null) {
123130
throw new IllegalArgumentException("store must not be null");
124131
}
@@ -190,26 +197,26 @@ private byte[] unwrap(byte[] content) throws DataConverterException {
190197
case INLINE_PREFIX:
191198
return body;
192199
case OFFLOAD_PREFIX:
193-
String key = extractS3Ref(body);
200+
String key = extractBlobRef(body);
194201
try {
195202
return store.get(key);
196203
} catch (IOException e) {
197204
throw new DataConverterException(
198-
"s3 offload: failed to fetch payload from blob store (key=" + key + ")", e);
205+
"claimcheck: failed to fetch payload from blob store (key=" + key + ")", e);
199206
}
200207
default:
201208
throw new DataConverterException(
202-
"s3 offload: unknown prefix byte 0x" + String.format("%02x", prefix & 0xff), null);
209+
"claimcheck: unknown prefix byte 0x" + String.format("%02x", prefix & 0xff), null);
203210
}
204211
}
205212

206-
private static String extractS3Ref(byte[] envelopeJson) throws DataConverterException {
213+
private static String extractBlobRef(byte[] envelopeJson) throws DataConverterException {
207214
BlobReference reference =
208215
delegate.fromData(envelopeJson, BlobReference.class, BlobReference.class);
209-
if (reference == null || reference.s3Ref == null || reference.s3Ref.isEmpty()) {
210-
throw new DataConverterException("s3 offload: envelope missing s3Ref field", null);
216+
if (reference == null || reference.blobRef == null || reference.blobRef.isEmpty()) {
217+
throw new DataConverterException("claimcheck: envelope missing blobRef field", null);
211218
}
212-
return reference.s3Ref;
219+
return reference.blobRef;
213220
}
214221

215222
private static String sha256Hex(byte[] data) throws DataConverterException {

src/main/java/com/uber/cadence/samples/s3offload/S3OffloadDataConverterWorkflow.java renamed to src/main/java/com/uber/cadence/samples/claimcheck/ClaimCheckDataConverterWorkflow.java

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* permissions and limitations under the License.
1616
*/
1717

18-
package com.uber.cadence.samples.s3offload;
18+
package com.uber.cadence.samples.claimcheck;
1919

2020
import com.uber.cadence.activity.ActivityMethod;
2121
import com.uber.cadence.activity.ActivityOptions;
@@ -34,55 +34,55 @@
3434
* <p>The workflow takes no inputs and builds a payload well above the threshold internally so it
3535
* can be started from the Cadence CLI and every run exercises the offload path.
3636
*/
37-
public final class S3OffloadDataConverterWorkflow {
37+
public final class ClaimCheckDataConverterWorkflow {
3838

39-
private S3OffloadDataConverterWorkflow() {}
39+
private ClaimCheckDataConverterWorkflow() {}
4040

41-
/** Task list polled by {@link S3OffloadWorker}. */
42-
public static final String TASK_LIST = "data-s3";
41+
/** Task list polled by {@link ClaimCheckWorker}. */
42+
public static final String TASK_LIST = "data-claimcheck";
4343

4444
/**
4545
* Registered workflow type, used for both {@code @WorkflowMethod} and CLI {@code workflow start}.
4646
*/
47-
public static final String WORKFLOW_TYPE = "S3OffloadDataConverterWorkflow";
47+
public static final String WORKFLOW_TYPE = "ClaimCheckDataConverterWorkflow";
4848

49-
/** Logical bucket / prefix embedded in S3-offload reference keys. */
50-
public static final String S3_BUCKET = "data-s3";
49+
/** Logical bucket / prefix embedded in claim-check reference keys. */
50+
public static final String BLOB_BUCKET = "claimcheck-blobs";
5151

5252
/**
53-
* Payloads larger than this are offloaded to the BlobStore by {@link S3OffloadDataConverter}.
53+
* Payloads larger than this are offloaded to the BlobStore by {@link ClaimCheckDataConverter}.
5454
* Cadence's default max payload is roughly 2 MB; the threshold is set intentionally low so the
5555
* demo workflow comfortably triggers offloading.
5656
*/
5757
public static final int DEFAULT_THRESHOLD_BYTES = 4096;
5858

5959
// ---------------- POJOs ----------------
6060

61-
public static final class S3LargePayload {
61+
public static final class LargePayload {
6262
public String jobId;
6363
public String description;
64-
public List<S3DataPoint> dataPoints;
64+
public List<DataPoint> dataPoints;
6565
public Map<String, String> metadata;
6666
public String processedBy;
6767

68-
public S3LargePayload() {}
68+
public LargePayload() {}
6969
}
7070

71-
public static final class S3DataPoint {
71+
public static final class DataPoint {
7272
public String timestamp;
7373
public String metric;
7474
public double value;
7575
public String tags;
7676

77-
public S3DataPoint() {}
77+
public DataPoint() {}
7878
}
7979

8080
/**
8181
* Builds a payload comfortably larger than {@link #DEFAULT_THRESHOLD_BYTES} so every workflow run
8282
* triggers an offload.
8383
*/
84-
public static S3LargePayload createS3LargePayload() {
85-
S3LargePayload p = new S3LargePayload();
84+
public static LargePayload createLargePayload() {
85+
LargePayload p = new LargePayload();
8686
p.jobId = "batch-job-20240115-001";
8787
p.description =
8888
repeat(
@@ -91,7 +91,7 @@ public static S3LargePayload createS3LargePayload() {
9191

9292
p.dataPoints = new ArrayList<>(200);
9393
for (int i = 0; i < 200; i++) {
94-
S3DataPoint dp = new S3DataPoint();
94+
DataPoint dp = new DataPoint();
9595
dp.timestamp = String.format("2024-01-15T%02d:30:00Z", i % 24);
9696
dp.metric = String.format("telemetry.sensor_%03d.temperature", i);
9797
dp.value = 20.0 + (i % 30) / 10.0;
@@ -103,7 +103,7 @@ public static S3LargePayload createS3LargePayload() {
103103
for (int i = 0; i < 20; i++) {
104104
p.metadata.put(String.format("batch_key_%02d", i), repeat("value-data-", 5));
105105
}
106-
p.processedBy = "s3-offload-worker-v1";
106+
p.processedBy = "claimcheck-worker-v1";
107107
return p;
108108
}
109109

@@ -124,13 +124,13 @@ public interface WorkflowIface {
124124
executionStartToCloseTimeoutSeconds = 60,
125125
taskList = TASK_LIST
126126
)
127-
S3LargePayload run();
127+
LargePayload run();
128128
}
129129

130130
public interface Activities {
131131

132132
@ActivityMethod(scheduleToCloseTimeoutSeconds = 60)
133-
S3LargePayload processS3Payload(S3LargePayload payload);
133+
LargePayload processPayload(LargePayload payload);
134134
}
135135

136136
public static final class WorkflowImpl implements WorkflowIface {
@@ -144,20 +144,20 @@ public static final class WorkflowImpl implements WorkflowIface {
144144
.build());
145145

146146
@Override
147-
public S3LargePayload run() {
148-
S3LargePayload payload = createS3LargePayload();
147+
public LargePayload run() {
148+
LargePayload payload = createLargePayload();
149149

150-
Workflow.getLogger(S3OffloadDataConverterWorkflow.class)
150+
Workflow.getLogger(ClaimCheckDataConverterWorkflow.class)
151151
.info(
152-
"S3 offload workflow started: job_id={}, data_points={}. Payload will be offloaded; only a reference travels through Cadence history.",
152+
"Claim-check workflow started: job_id={}, data_points={}. Payload will be offloaded; only a reference travels through Cadence history.",
153153
payload.jobId,
154154
payload.dataPoints.size());
155155

156-
S3LargePayload result = activities.processS3Payload(payload);
156+
LargePayload result = activities.processPayload(payload);
157157

158-
Workflow.getLogger(S3OffloadDataConverterWorkflow.class)
158+
Workflow.getLogger(ClaimCheckDataConverterWorkflow.class)
159159
.info(
160-
"S3 offload workflow completed: job_id={}. Payload was transparently offloaded and retrieved via the BlobStore.",
160+
"Claim-check workflow completed: job_id={}. Payload was transparently offloaded and retrieved via the BlobStore.",
161161
result.jobId);
162162
return result;
163163
}
@@ -166,7 +166,7 @@ public S3LargePayload run() {
166166
public static final class ActivitiesImpl implements Activities {
167167

168168
@Override
169-
public S3LargePayload processS3Payload(S3LargePayload payload) {
169+
public LargePayload processPayload(LargePayload payload) {
170170
payload.processedBy = payload.processedBy + " (Processed)";
171171
return payload;
172172
}

src/main/java/com/uber/cadence/samples/s3offload/S3OffloadStarter.java renamed to src/main/java/com/uber/cadence/samples/claimcheck/ClaimCheckStarter.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* permissions and limitations under the License.
1616
*/
1717

18-
package com.uber.cadence.samples.s3offload;
18+
package com.uber.cadence.samples.claimcheck;
1919

2020
import com.uber.cadence.client.WorkflowClient;
2121
import com.uber.cadence.client.WorkflowClientOptions;
@@ -27,23 +27,23 @@
2727
import java.util.UUID;
2828

2929
/**
30-
* Starts {@link S3OffloadDataConverterWorkflow} (async, fire-and-forget).
30+
* Starts {@link ClaimCheckDataConverterWorkflow} (async, fire-and-forget).
3131
*
3232
* <p>The workflow takes no inputs and generates its own payload, so this starter does not need to
33-
* use the matching {@link S3OffloadDataConverter}. The same effect can be achieved from the Cadence
34-
* CLI via:
33+
* use the matching {@link ClaimCheckDataConverter}. The same effect can be achieved from the
34+
* Cadence CLI via:
3535
*
3636
* <pre>
3737
* cadence --domain samples-domain \
3838
* workflow start \
39-
* --workflow_type S3OffloadDataConverterWorkflow \
40-
* --tl data-s3 \
39+
* --workflow_type ClaimCheckDataConverterWorkflow \
40+
* --tl data-claimcheck \
4141
* --et 60
4242
* </pre>
4343
*/
44-
public final class S3OffloadStarter {
44+
public final class ClaimCheckStarter {
4545

46-
private S3OffloadStarter() {}
46+
private ClaimCheckStarter() {}
4747

4848
public static void main(String[] args) {
4949
try {
@@ -53,20 +53,20 @@ public static void main(String[] args) {
5353
WorkflowClientOptions.newBuilder().setDomain(SampleConstants.DOMAIN).build());
5454
WorkflowOptions options =
5555
new WorkflowOptions.Builder()
56-
.setTaskList(S3OffloadDataConverterWorkflow.TASK_LIST)
56+
.setTaskList(ClaimCheckDataConverterWorkflow.TASK_LIST)
5757
.setExecutionStartToCloseTimeout(Duration.ofMinutes(1))
58-
.setWorkflowId("s3-offload-" + UUID.randomUUID())
58+
.setWorkflowId("claimcheck-" + UUID.randomUUID())
5959
.build();
6060

61-
S3OffloadDataConverterWorkflow.WorkflowIface workflow =
62-
client.newWorkflowStub(S3OffloadDataConverterWorkflow.WorkflowIface.class, options);
61+
ClaimCheckDataConverterWorkflow.WorkflowIface workflow =
62+
client.newWorkflowStub(ClaimCheckDataConverterWorkflow.WorkflowIface.class, options);
6363

6464
WorkflowClient.start(workflow::run);
6565
System.out.println(
6666
"Started "
67-
+ S3OffloadDataConverterWorkflow.WORKFLOW_TYPE
67+
+ ClaimCheckDataConverterWorkflow.WORKFLOW_TYPE
6868
+ " on task list \""
69-
+ S3OffloadDataConverterWorkflow.TASK_LIST
69+
+ ClaimCheckDataConverterWorkflow.TASK_LIST
7070
+ "\".");
7171
System.exit(0);
7272
} catch (RuntimeException e) {

0 commit comments

Comments
 (0)