Skip to content

External Storage Integration: Lazy resolving references, general refactoring - #3016

Open
cconstable wants to merge 1 commit into
mainfrom
extstore/foundation
Open

External Storage Integration: Lazy resolving references, general refactoring#3016
cconstable wants to merge 1 commit into
mainfrom
extstore/foundation

Conversation

@cconstable

@cconstable cconstable commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

What was changed

  • Renames ExternalStorageMessageTransformer to ExternalStorage.
  • Adds a DataConverter decorator, ExternalStorageResolvingDataConverter, that does the external storage work and delegates to the existing data converter for everything else.
    • This means we defer extstore operations until values are actually needed (e.g. fromPayload). We don't eagerly load them.
    • This was implemented as a decorator because the existing data converter is used in the workflow sandbox (and extstore shouldn't be in there).

Why?

These changes support the following PRs:

  1. Workflow worker integration External Storage Integration: WorkflowWorker, replay, history #3017
  2. Nexus worker integration External Storage Integration: NexusWorker #3018
  3. Activity worker and client integration External Storage Integration: Activity worker, client #3020
  4. E2E extstore tests

Checklist

  • Added tests

@cconstable
cconstable force-pushed the extstore/foundation branch from 3fe47fb to 831c284 Compare August 18, 2026 21:03
private boolean allowActivityHeartbeatDuringShutdown;
private String workerControlTaskQueue;
private PreferredVersionProvider preferredVersionProvider;
private @Nullable ExternalStorage externalStorage;

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 doesn't have any callers in this PR but three of the PRs that build off this will use it. Included it here since those PRs are being up together.

…former to ExternalStorage, create a lazy extstore resolving data converter.
@cconstable
cconstable force-pushed the extstore/foundation branch from 831c284 to 460bfbf Compare August 19, 2026 17:40
@cconstable cconstable changed the title refactor(extstore): general extstore refactoring. rename MessageTransformer to ExternalStorage, create a lazy extstore resolving data converter. External Storage refactoring for workflow, activity, client, and nexus integration Aug 19, 2026
@cconstable cconstable changed the title External Storage refactoring for workflow, activity, client, and nexus integration External Storage Integration: general refactoring Aug 19, 2026
@cconstable cconstable changed the title External Storage Integration: general refactoring External Storage Integration: Lazy resolving references, general refactoring Aug 19, 2026
@cconstable
cconstable marked this pull request as ready for review August 19, 2026 18:57
@cconstable
cconstable requested a review from a team as a code owner August 19, 2026 18:57
}

if (ExternalStorageReferences.isReference(payload)) {
throw new ExternalStorageNotConfiguredException();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIUC, this looks to be a DataConverter, which means it runs within the workflow code context. This means that this exception is handleable by user code. I think we need to move this to somewhere before the workflow code executes so we can fail the workflow task without allowing the user code to compensate.

/**
* A {@link DataConverter} that resolves external storage reference payloads before deserialization.
*/
public final class ExternalStorageResolvingDataConverter implements DataConverter {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@Nonnull
@Override
public DataConverter withContext(@Nonnull SerializationContext context) {
return new ExternalStorageResolvingDataConverter(delegate, externalStorage, context);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't this call withContext on the delegate and then determine if a the outer ExternalStorageResolvingDataConverter truly needs to be reconstructed?


/**
* Maximum number of payload lists visited concurrently while offloading or restoring the
* payloads of a single message. Must be at least 1. Defaults to 3.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure a user is going to understand what is meant by "a single message". And "a single message" isn't quite the right scope from a implementation perspective. Maybe should describe this in terms of client operations and worker tasks.

}
}

<T extends Message> CompletableFuture<T> store(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are there legitimate places where we need to visit on the fully constructed message instead of the build (the next overload)? I presume that the caller already created a builder, constructed the message, then this would effective recreate another builder, and reconstruct the message again. Might be perf issues. I would check to see if we can drop the message overloads and only use the builder overloads to force callers into the better performing algorithm.

}
}

<T extends Message> CompletableFuture<T> store(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This will not work for workflow task completions because the nested commands need to change the the context when they are encountered. Having an outer visitor doing that determination and then calling this method is probably okay.

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