Skip to content

exstore/pipeline integration - #2978

Open
cconstable wants to merge 13 commits into
extstore-core-logicfrom
exstore/pipeline-integration
Open

exstore/pipeline integration#2978
cconstable wants to merge 13 commits into
extstore-core-logicfrom
exstore/pipeline-integration

Conversation

@cconstable

@cconstable cconstable commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Client + Nexus + Worker external storage integration

What was changed

  • enabled extstore via WorkflowClientOptions.setExternalStorage(...), worker/WorkerFactoryOptions, internal/worker/SingleWorkerOptions, and worker/Worker
  • client/worker with no external storage configured fails with TMPRL-1105
  • Client: integration via new decorator ExternalStorageGenericWorkflowClient that is used in client/WorkflowClientInternalImpl
  • Workers: integration via internal/worker/{WorkflowWorker,ActivityWorker,NexusWorker} and internal/replay/{ServiceWorkflowHistoryIterator,ReplayWorkflowTaskHandler}
  • Activity completion + heartbeat integration.

Why?

  • makes extstore "work" in client, worker, and nexus pipelines

Checklist

  • Added new tests

@cconstable
cconstable changed the base branch from main to extstore-core-logic July 29, 2026 21:07
@cconstable
cconstable marked this pull request as ready for review July 30, 2026 19:42
@cconstable
cconstable requested a review from a team as a code owner July 30, 2026 19:42
@cconstable
cconstable requested a review from Copilot July 30, 2026 19:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end external storage (“extstore”) support across the Java SDK client and worker execution pipelines (including Nexus) by introducing message-level payload offload/restore and clear failure behavior when references are encountered without extstore configured.

Changes:

  • Introduces WorkflowClientOptions.setExternalStorage(...) integration via a ExternalStorageGenericWorkflowClient decorator and worker-side wiring through SingleWorkerOptions and worker implementations.
  • Adds worker/client plumbing to offload outbound payloads, restore inbound payloads, and propagate TMPRL-1105 consistently when references reach deserialization without extstore configured.
  • Expands tests to cover pipeline round-trips, concurrency bounds, interrupt behavior, and manual activity completion/heartbeat integration.

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
temporal-testing/src/main/java/io/temporal/testing/TestActivityEnvironmentInternal.java Updates activity test environment wiring for new activity context factory signature (currently passes null extstore converter).
temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStoragePipelineTest.java New end-to-end pipeline test validating store/retrieve behavior through client + worker execution.
temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageMessageConverterTest.java Adds tests for visit concurrency bounding and interrupt handling in blocking store.
temporal-sdk/src/test/java/io/temporal/internal/client/external/ManualActivityCompletionClientImplTest.java New tests ensuring manual completion wraps/ignores storage failures appropriately.
temporal-sdk/src/test/java/io/temporal/internal/client/external/ExternalStorageGenericWorkflowClientTest.java New tests validating target info propagation for standalone activity start and multi-operation.
temporal-sdk/src/test/java/io/temporal/internal/activity/HeartbeatContextImplTest.java Updates tests for new constructor parameters (extstore converter).
temporal-sdk/src/test/java/io/temporal/internal/activity/ActivityExecutionContextImplTest.java New test validating local manual completion includes activity storage target info.
temporal-sdk/src/test/java/io/temporal/common/converter/ExternalStorageReferenceGuardTest.java New tests validating [TMPRL-1105] guard behavior when extstore isn’t configured.
temporal-sdk/src/main/java/io/temporal/worker/WorkerFactoryOptions.java Adds max concurrent external-storage visit option and exposes it via getter/builder.
temporal-sdk/src/main/java/io/temporal/worker/Worker.java Wires client external storage config into worker SingleWorkerOptions via message converter creation.
temporal-sdk/src/main/java/io/temporal/payload/storage/StorageDriver.java Clarifies driver expectations around cancellation + backend timeouts (SDK imposes no timeout).
temporal-sdk/src/main/java/io/temporal/internal/worker/WorkflowWorker.java Offloads outbound workflow task/query completion payloads with workflow target context.
temporal-sdk/src/main/java/io/temporal/internal/worker/SyncActivityWorker.java Passes extstore message converter into activity execution context factory.
temporal-sdk/src/main/java/io/temporal/internal/worker/SingleWorkerOptions.java Adds optional external storage message converter to per-worker options.
temporal-sdk/src/main/java/io/temporal/internal/worker/NexusWorker.java Adds inbound restore + outbound offload for Nexus task handling.
temporal-sdk/src/main/java/io/temporal/internal/worker/ActivityWorker.java Adds inbound restore + outbound offload for activity task handling, including activity target context.
temporal-sdk/src/main/java/io/temporal/internal/sync/WorkflowExecutionHandler.java Ensures missing-extstore failures propagate cleanly rather than being wrapped/obscured.
temporal-sdk/src/main/java/io/temporal/internal/sync/SignalDispatcher.java Propagates missing-extstore failures distinctly from generic DataConverterException.
temporal-sdk/src/main/java/io/temporal/internal/replay/ServiceWorkflowHistoryIterator.java Adds optional extstore restoration when paging history during replay.
temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowTaskHandler.java Restores inbound WFT payloads and replay history when extstore is enabled; propagates missing-extstore error.
temporal-sdk/src/main/java/io/temporal/internal/payload/storage/ExternalStorageNotConfiguredException.java New exception type for [TMPRL-1105] missing-extstore failures with helper find(...).
temporal-sdk/src/main/java/io/temporal/internal/payload/storage/ExternalStorageMessageConverter.java Makes message converter public (internal package), adds factory methods and blocking store/retrieve helpers.
temporal-sdk/src/main/java/io/temporal/internal/nexus/NexusTaskHandlerImpl.java Propagates missing-extstore failures from Nexus handler execution.
temporal-sdk/src/main/java/io/temporal/internal/client/external/ManualActivityCompletionClientImpl.java Offloads manual completion and heartbeat payloads; adds storage target + converter plumbing.
temporal-sdk/src/main/java/io/temporal/internal/client/external/ManualActivityCompletionClientFactoryImpl.java Adds storage target computation and passes extstore converter into manual completion clients.
temporal-sdk/src/main/java/io/temporal/internal/client/external/ManualActivityCompletionClientFactory.java Adds overloads to supply extstore converter and explicit storage target info.
temporal-sdk/src/main/java/io/temporal/internal/client/external/ExternalStorageGenericWorkflowClient.java New client decorator that offloads outbound and restores inbound payloads for many service calls.
temporal-sdk/src/main/java/io/temporal/internal/client/ActivityClientHelper.java Offloads heartbeat request details when extstore is configured.
temporal-sdk/src/main/java/io/temporal/internal/activity/HeartbeatContextImpl.java Adds extstore-aware heartbeat sending with activity storage target info.
temporal-sdk/src/main/java/io/temporal/internal/activity/ActivityTaskExecutors.java Propagates missing-extstore failures distinctly during activity execution.
temporal-sdk/src/main/java/io/temporal/internal/activity/ActivityExecutionContextImpl.java Passes extstore converter into heartbeat context and provides storage target for local manual completion.
temporal-sdk/src/main/java/io/temporal/internal/activity/ActivityExecutionContextFactoryImpl.java Stores extstore converter and wires it into contexts and manual completion factory.
temporal-sdk/src/main/java/io/temporal/common/converter/PayloadAndFailureDataConverter.java Adds guard: reference payloads reaching deserialization without extstore configured throw [TMPRL-1105].
temporal-sdk/src/main/java/io/temporal/client/WorkflowClientOptions.java Adds user-facing external storage options field with builder/getter + equality/toString updates.
temporal-sdk/src/main/java/io/temporal/client/WorkflowClientInternalImpl.java Wraps generic client with extstore decorator and passes extstore converter into manual completion factory.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 111 to +113
testEnvironmentOptions.getWorkflowClientOptions().getDataConverter(),
heartbeatExecutor);
heartbeatExecutor,
null);
Comment on lines +180 to +184
* Maximum number of concurrent payload-list visits performed while offloading or restoring
* external-storage payloads for a single worker task. Only applies when external storage is
* configured on the client. Must be at least 1.
*
* <p>Default is 3.
payloads.ifPresent(request::setDetails);
payloads.ifPresent(builder::setDetails);
RecordActivityTaskHeartbeatRequest request = builder.build();
if (externalStorage != null) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This covers both worker and manual heartbeats


ServiceWorkflowHistoryIterator historyIterator =
new ServiceWorkflowHistoryIterator(service, namespace, workflowTask, metricsScope);
new ServiceWorkflowHistoryIterator(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this used by the worker?

Comment on lines +140 to +144
ExternalStorageNotConfiguredException externalStorageFailure =
ExternalStorageNotConfiguredException.find(e);
if (externalStorageFailure != null) {
throw externalStorageFailure;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets look at how other errors are being handled here and make sure we aren't special-casing extstore errors

.setIdentity(options.getIdentity())
.setNamespace(namespace)
.setWorkerVersion(options.workerVersionStamp())
.build(),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmaeagle99 suggests looking at passing through builders to visitor. are there perf concerns? are we building messages twice? @cconstable will investigate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants