diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a35074873..74e1871b90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,11 +20,21 @@ to docs, or any other relevant information. ## [Unreleased] ### :boom: Breaking Changes +- `WorkflowOutboundCallsInterceptor` now includes generated system Nexus operation hooks. + Direct implementations must implement the hooks; extending `WorkflowOutboundCallsInterceptorBase` + provides forwarding implementations. - `WorkflowOutboundCallsInterceptor` has new `sleep(Duration, TimerOptions)` and `await(Duration, TimerOptions, String, Supplier)` methods. Implementations that don't extend `WorkflowOutboundCallsInterceptorBase` need to add them, and Base subclasses override them to see calls with options. ### Added +- Workflows can signal with start through the system workflow service using + generated `Workflow.signalWithStartWorkflow(workflowType, args, workflowId, taskQueue, signalName, signalArgs, options)` API. + Typed overloads accept bound workflow/signal methods followed directly by checked arguments. + Typed calls merge workflow retry/cron annotations with explicit options using generated Java-only WIT hooks. + Request builders and operations are generated into `io.temporal.workflow`. + System Nexus envelopes preserve destination workflow serialization context for nested payloads, + codecs, and external payload storage. Requires a server supporting the system workflow service. - Applications can use the experimental `@TransferTypeConvertible` annotation and `TransferTypeConverter` interface to convert top-level model values to transfer types. The SDK applies this conversion to workflow, activity, Nexus, and schedule payloads, including failure diff --git a/temporal-sdk/build.gradle b/temporal-sdk/build.gradle index d74bb1c7cc..11011fd70f 100644 --- a/temporal-sdk/build.gradle +++ b/temporal-sdk/build.gradle @@ -42,6 +42,7 @@ dependencies { // we need to compile the code with Java 21 and package it in a multi-release jar. // Similarly, Jackson 3 support requires Java 17+ and is compiled separately. sourceSets { + main.java.srcDir 'src/main/generated' java17 { java { srcDirs = ['src/main/java17'] @@ -335,3 +336,38 @@ tasks.named('check') { dependsOn(testing.suites.jackson3Tests) dependsOn(testing.suites.virtualThreadTests) } + +// Explicit regeneration keeps normal SDK builds independent of the Rust toolchain. +// Use -PnexgenBinary=/path/to/nexgen to test an unreleased generator. +def nexusGeneratedDir = layout.buildDirectory.dir('generated/nexus/workflow').get().asFile +def nexusCheckedInDir = file('src/main/generated/io/temporal/workflow') +tasks.register('generateNexusSystemApi', Exec) { + dependsOn ':temporal-serviceclient:generateProto' + def binary = providers.gradleProperty('nexgenBinary').orElse('nexgen') + inputs.dir('src/main/nexus') + inputs.file(project(':temporal-serviceclient').layout.buildDirectory.file('generated/descriptors/temporal-api.desc')) + inputs.property('nexgenVersion', '0.2.9') + outputs.dir(nexusGeneratedDir) + outputs.upToDateWhen { false } + commandLine binary.get(), 'java', file('src/main/nexus/workflow-service.wit'), + file('src/main/nexus/deps'), '--native-api', '--system-nexus', '--format', + '--support-package', 'io.temporal.internal.nexus.system.TemporalModelConverters', + '--package-name', 'io.temporal.workflow', + '--descriptors', project(':temporal-serviceclient').layout.buildDirectory.file('generated/descriptors/temporal-api.desc').get().asFile, + '--output', nexusGeneratedDir + doFirst { + def versionOutput = new ByteArrayOutputStream() + project.exec { invocation -> + invocation.commandLine(binary.get(), '--version') + invocation.standardOutput = versionOutput + } + if (versionOutput.toString('UTF-8').trim() != 'nexgen 0.2.9') { + throw new GradleException('System Nexus regeneration requires nexgen 0.2.9 with the advanced feature.') + } + delete nexusGeneratedDir + } + doLast { project.sync { spec -> spec.from(nexusGeneratedDir); spec.into(nexusCheckedInDir) } } +} +tasks.matching { it.name == 'compileJava' || it.name.startsWith('spotless') }.configureEach { + mustRunAfter 'generateNexusSystemApi' +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java new file mode 100644 index 0000000000..7fd49cfaa1 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java @@ -0,0 +1,19 @@ +// Generated by nexgen. DO NOT EDIT! +package io.temporal.workflow; + +/** Shared conversion helpers used by these generated models. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class NexgenRuntime { + private NexgenRuntime() {} + + public static java.util.List decodeSequence( + io.temporal.api.common.v1.Payloads payloads, + io.temporal.common.converter.DataConverter converter, + Class elementClass, + java.lang.reflect.Type elementType) { + java.util.List result = new java.util.ArrayList<>(); + for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) + result.add(converter.fromPayload(payload, elementClass, elementType)); + return result; + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java new file mode 100644 index 0000000000..0811f712e7 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java @@ -0,0 +1,303 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Signal a workflow, starting it first if needed. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SignalWithStartWorkflowOptions { + /** + * Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited. + */ + private final java.time.Duration executionTimeout; + + /** Timeout of a single workflow run. Defaults to the workflow execution timeout. */ + private final java.time.Duration runTimeout; + + /** Timeout of a single workflow task. Defaults to 10 seconds. */ + private final java.time.Duration taskTimeout; + + /** Behavior when a closed workflow with the same ID exists. Default is allow-duplicate. */ + private final io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy; + + /** + * Behavior when a workflow is currently running with the same ID. Set to use-existing for + * idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is + * terminate-if-running. Defaults to use-existing. + */ + private final io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy; + + /** Retry policy for the workflow. */ + private final io.temporal.common.RetryOptions retryPolicy; + + /** Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job. */ + private final String cronSchedule; + + /** Memo for the workflow. */ + private final java.util.Map memo; + + /** Typed search attributes for the workflow. */ + private final io.temporal.common.SearchAttributes searchAttributes; + + /** Priority of the workflow execution. */ + private final io.temporal.common.Priority priority; + + /** Override for workflow versioning behavior. */ + private final io.temporal.common.VersioningOverride versioningOverride; + + /** Amount of time to wait before starting the workflow. This does not work with cron-schedule. */ + private final java.time.Duration startDelay; + + /** + * Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be + * in single-line Temporal Markdown format. + */ + private final String staticSummary; + + /** + * General fixed details for the workflow execution that may appear in UI and CLI. This can be in + * Temporal Markdown format and can span multiple lines. This value is fixed on the workflow + * execution and cannot be updated. + */ + private final String staticDetails; + + public static SignalWithStartWorkflowOptions getDefaultInstance() { + return SignalWithStartWorkflowOptions.newBuilder().build(); + } + + private SignalWithStartWorkflowOptions( + java.time.Duration executionTimeout, + java.time.Duration runTimeout, + java.time.Duration taskTimeout, + io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, + io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, + io.temporal.common.RetryOptions retryPolicy, + String cronSchedule, + java.util.Map memo, + io.temporal.common.SearchAttributes searchAttributes, + io.temporal.common.Priority priority, + io.temporal.common.VersioningOverride versioningOverride, + java.time.Duration startDelay, + String staticSummary, + String staticDetails) { + this.executionTimeout = executionTimeout; + this.runTimeout = runTimeout; + this.taskTimeout = taskTimeout; + this.idReusePolicy = idReusePolicy; + this.idConflictPolicy = idConflictPolicy; + this.retryPolicy = retryPolicy; + this.cronSchedule = cronSchedule; + this.memo = memo; + this.searchAttributes = searchAttributes; + this.priority = priority; + this.versioningOverride = versioningOverride; + this.startDelay = startDelay; + this.staticSummary = staticSummary; + this.staticDetails = staticDetails; + } + + public java.time.Duration getExecutionTimeout() { + return executionTimeout; + } + + public java.time.Duration getRunTimeout() { + return runTimeout; + } + + public java.time.Duration getTaskTimeout() { + return taskTimeout; + } + + public io.temporal.api.enums.v1.WorkflowIdReusePolicy getIdReusePolicy() { + return idReusePolicy; + } + + public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getIdConflictPolicy() { + return idConflictPolicy; + } + + public io.temporal.common.RetryOptions getRetryPolicy() { + return retryPolicy; + } + + public String getCronSchedule() { + return cronSchedule; + } + + public java.util.Map getMemo() { + return memo; + } + + public io.temporal.common.SearchAttributes getSearchAttributes() { + return searchAttributes; + } + + public io.temporal.common.Priority getPriority() { + return priority; + } + + public io.temporal.common.VersioningOverride getVersioningOverride() { + return versioningOverride; + } + + public java.time.Duration getStartDelay() { + return startDelay; + } + + public String getStaticSummary() { + return staticSummary; + } + + public String getStaticDetails() { + return staticDetails; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(SignalWithStartWorkflowOptions value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private Builder() {} + + private Builder(SignalWithStartWorkflowOptions value) { + if (value == null) return; + this.executionTimeout = value.executionTimeout; + this.runTimeout = value.runTimeout; + this.taskTimeout = value.taskTimeout; + this.idReusePolicy = value.idReusePolicy; + this.idConflictPolicy = value.idConflictPolicy; + this.retryPolicy = value.retryPolicy; + this.cronSchedule = value.cronSchedule; + this.memo = value.memo; + this.searchAttributes = value.searchAttributes; + this.priority = value.priority; + this.versioningOverride = value.versioningOverride; + this.startDelay = value.startDelay; + this.staticSummary = value.staticSummary; + this.staticDetails = value.staticDetails; + } + + private java.time.Duration executionTimeout = null; + + public Builder setExecutionTimeout(java.time.Duration value) { + this.executionTimeout = value; + return this; + } + + private java.time.Duration runTimeout = null; + + public Builder setRunTimeout(java.time.Duration value) { + this.runTimeout = value; + return this; + } + + private java.time.Duration taskTimeout = null; + + public Builder setTaskTimeout(java.time.Duration value) { + this.taskTimeout = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy = + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(1); + + public Builder setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { + this.idReusePolicy = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy = null; + + public Builder setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { + this.idConflictPolicy = value; + return this; + } + + private io.temporal.common.RetryOptions retryPolicy = null; + + public Builder setRetryPolicy(io.temporal.common.RetryOptions value) { + this.retryPolicy = value; + return this; + } + + private String cronSchedule = null; + + public Builder setCronSchedule(String value) { + this.cronSchedule = value; + return this; + } + + private java.util.Map memo = null; + + public Builder setMemo(java.util.Map value) { + this.memo = value; + return this; + } + + private io.temporal.common.SearchAttributes searchAttributes = null; + + public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { + this.searchAttributes = value; + return this; + } + + private io.temporal.common.Priority priority = null; + + public Builder setPriority(io.temporal.common.Priority value) { + this.priority = value; + return this; + } + + private io.temporal.common.VersioningOverride versioningOverride = null; + + public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { + this.versioningOverride = value; + return this; + } + + private java.time.Duration startDelay = null; + + public Builder setStartDelay(java.time.Duration value) { + this.startDelay = value; + return this; + } + + private String staticSummary = null; + + public Builder setStaticSummary(String value) { + this.staticSummary = value; + return this; + } + + private String staticDetails = null; + + public Builder setStaticDetails(String value) { + this.staticDetails = value; + return this; + } + + public SignalWithStartWorkflowOptions build() { + return new SignalWithStartWorkflowOptions( + executionTimeout, + runTimeout, + taskTimeout, + idReusePolicy, + idConflictPolicy, + retryPolicy, + cronSchedule, + memo, + searchAttributes, + priority, + versioningOverride, + startDelay, + staticSummary, + staticDetails); + } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java new file mode 100644 index 0000000000..daf7a67246 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java @@ -0,0 +1,630 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Request fields for signaling a workflow, starting it first if needed. */ +@io.temporal.common.converter.TransferTypeConvertible( + SignalWithStartWorkflowRequest.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SignalWithStartWorkflowRequest { + private final String workflow; + + /** Arguments for the workflow. */ + private final java.util.List args; + + /** Unique identifier for the workflow execution. Must be nonempty. */ + private final String id; + + /** Task queue to run the workflow on. */ + private final String taskQueue; + + private final String signal; + + /** Arguments for the signal. */ + private final java.util.List signalArgs; + + /** + * Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited. + */ + private final java.time.Duration executionTimeout; + + /** Timeout of a single workflow run. Defaults to the workflow execution timeout. */ + private final java.time.Duration runTimeout; + + /** Timeout of a single workflow task. Defaults to 10 seconds. */ + private final java.time.Duration taskTimeout; + + /** Behavior when a closed workflow with the same ID exists. Default is allow-duplicate. */ + private final io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy; + + /** + * Behavior when a workflow is currently running with the same ID. Set to use-existing for + * idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is + * terminate-if-running. Defaults to use-existing. + */ + private final io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy; + + /** Retry policy for the workflow. */ + private final io.temporal.common.RetryOptions retryPolicy; + + /** Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job. */ + private final String cronSchedule; + + /** Memo for the workflow. */ + private final java.util.Map memo; + + /** Typed search attributes for the workflow. */ + private final io.temporal.common.SearchAttributes searchAttributes; + + /** Priority of the workflow execution. */ + private final io.temporal.common.Priority priority; + + /** Override for workflow versioning behavior. */ + private final io.temporal.common.VersioningOverride versioningOverride; + + /** Amount of time to wait before starting the workflow. This does not work with cron-schedule. */ + private final java.time.Duration startDelay; + + /** Static metadata for the workflow execution. */ + private final io.temporal.workflow.UserMetadata userMetadata; + + /** Namespace of the workflow execution. */ + private final String namespace; + + /** Headers for the request. */ + private final java.util.Map headers; + + @com.fasterxml.jackson.annotation.JsonCreator + public SignalWithStartWorkflowRequest( + @com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, + @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, + @com.fasterxml.jackson.annotation.JsonProperty("id") String id, + @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, + @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, + @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") + java.util.List signalArgs, + @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") + java.time.Duration executionTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("taskTimeout") java.time.Duration taskTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("idReusePolicy") + io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, + @com.fasterxml.jackson.annotation.JsonProperty("idConflictPolicy") + io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, + @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") + io.temporal.common.RetryOptions retryPolicy, + @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, + @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, + @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") + io.temporal.common.SearchAttributes searchAttributes, + @com.fasterxml.jackson.annotation.JsonProperty("priority") + io.temporal.common.Priority priority, + @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") + io.temporal.common.VersioningOverride versioningOverride, + @com.fasterxml.jackson.annotation.JsonProperty("startDelay") java.time.Duration startDelay, + @com.fasterxml.jackson.annotation.JsonProperty("userMetadata") + io.temporal.workflow.UserMetadata userMetadata, + @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, + @com.fasterxml.jackson.annotation.JsonProperty("headers") + java.util.Map headers) { + this.workflow = workflow; + this.args = args; + this.id = id; + this.taskQueue = taskQueue; + this.signal = signal; + this.signalArgs = signalArgs; + this.executionTimeout = executionTimeout; + this.runTimeout = runTimeout; + this.taskTimeout = taskTimeout; + this.idReusePolicy = idReusePolicy; + this.idConflictPolicy = idConflictPolicy; + this.retryPolicy = retryPolicy; + this.cronSchedule = cronSchedule; + this.memo = memo; + this.searchAttributes = searchAttributes; + this.priority = priority; + this.versioningOverride = versioningOverride; + this.startDelay = startDelay; + this.userMetadata = userMetadata; + this.namespace = namespace; + this.headers = headers; + } + + public String getWorkflow() { + return workflow; + } + + public java.util.List getArgs() { + return args; + } + + public String getId() { + return id; + } + + public String getTaskQueue() { + return taskQueue; + } + + public String getSignal() { + return signal; + } + + public java.util.List getSignalArgs() { + return signalArgs; + } + + public java.time.Duration getExecutionTimeout() { + return executionTimeout; + } + + public java.time.Duration getRunTimeout() { + return runTimeout; + } + + public java.time.Duration getTaskTimeout() { + return taskTimeout; + } + + public io.temporal.api.enums.v1.WorkflowIdReusePolicy getIdReusePolicy() { + return idReusePolicy; + } + + public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getIdConflictPolicy() { + return idConflictPolicy; + } + + public io.temporal.common.RetryOptions getRetryPolicy() { + return retryPolicy; + } + + public String getCronSchedule() { + return cronSchedule; + } + + public java.util.Map getMemo() { + return memo; + } + + public io.temporal.common.SearchAttributes getSearchAttributes() { + return searchAttributes; + } + + public io.temporal.common.Priority getPriority() { + return priority; + } + + public io.temporal.common.VersioningOverride getVersioningOverride() { + return versioningOverride; + } + + public java.time.Duration getStartDelay() { + return startDelay; + } + + public io.temporal.workflow.UserMetadata getUserMetadata() { + return userMetadata; + } + + public String getNamespace() { + return namespace; + } + + public java.util.Map getHeaders() { + return headers; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(SignalWithStartWorkflowRequest value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private Builder() {} + + private Builder(SignalWithStartWorkflowRequest value) { + if (value == null) return; + this.workflow = value.workflow; + this.args = value.args; + this.id = value.id; + this.taskQueue = value.taskQueue; + this.signal = value.signal; + this.signalArgs = value.signalArgs; + this.executionTimeout = value.executionTimeout; + this.runTimeout = value.runTimeout; + this.taskTimeout = value.taskTimeout; + this.idReusePolicy = value.idReusePolicy; + this.idConflictPolicy = value.idConflictPolicy; + this.retryPolicy = value.retryPolicy; + this.cronSchedule = value.cronSchedule; + this.memo = value.memo; + this.searchAttributes = value.searchAttributes; + this.priority = value.priority; + this.versioningOverride = value.versioningOverride; + this.startDelay = value.startDelay; + this.userMetadata = value.userMetadata; + this.namespace = value.namespace; + this.headers = value.headers; + } + + private String workflow = null; + + public Builder setWorkflow(String value) { + this.workflow = value; + return this; + } + + private java.util.List args = null; + + public Builder setArgs(java.util.List value) { + this.args = value; + return this; + } + + private String id = ""; + + public Builder setId(String value) { + this.id = value; + return this; + } + + private String taskQueue = null; + + public Builder setTaskQueue(String value) { + this.taskQueue = value; + return this; + } + + private String signal = ""; + + public Builder setSignal(String value) { + this.signal = value; + return this; + } + + private java.util.List signalArgs = null; + + public Builder setSignalArgs(java.util.List value) { + this.signalArgs = value; + return this; + } + + private java.time.Duration executionTimeout = null; + + public Builder setExecutionTimeout(java.time.Duration value) { + this.executionTimeout = value; + return this; + } + + private java.time.Duration runTimeout = null; + + public Builder setRunTimeout(java.time.Duration value) { + this.runTimeout = value; + return this; + } + + private java.time.Duration taskTimeout = null; + + public Builder setTaskTimeout(java.time.Duration value) { + this.taskTimeout = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy = + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(1); + + public Builder setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { + this.idReusePolicy = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy = null; + + public Builder setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { + this.idConflictPolicy = value; + return this; + } + + private io.temporal.common.RetryOptions retryPolicy = null; + + public Builder setRetryPolicy(io.temporal.common.RetryOptions value) { + this.retryPolicy = value; + return this; + } + + private String cronSchedule = null; + + public Builder setCronSchedule(String value) { + this.cronSchedule = value; + return this; + } + + private java.util.Map memo = null; + + public Builder setMemo(java.util.Map value) { + this.memo = value; + return this; + } + + private io.temporal.common.SearchAttributes searchAttributes = null; + + public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { + this.searchAttributes = value; + return this; + } + + private io.temporal.common.Priority priority = null; + + public Builder setPriority(io.temporal.common.Priority value) { + this.priority = value; + return this; + } + + private io.temporal.common.VersioningOverride versioningOverride = null; + + public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { + this.versioningOverride = value; + return this; + } + + private java.time.Duration startDelay = null; + + public Builder setStartDelay(java.time.Duration value) { + this.startDelay = value; + return this; + } + + private io.temporal.workflow.UserMetadata userMetadata = null; + + public Builder setUserMetadata(io.temporal.workflow.UserMetadata value) { + this.userMetadata = value; + return this; + } + + private String namespace = null; + + public Builder setNamespace(String value) { + this.namespace = value; + return this; + } + + private java.util.Map headers = null; + + public Builder setHeaders(java.util.Map value) { + this.headers = value; + return this; + } + + public Builder setStaticSummary(String value) { + this.userMetadata = + io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata) + .setStaticSummary(value) + .build(); + return this; + } + + public Builder setStaticDetails(String value) { + this.userMetadata = + io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata) + .setStaticDetails(value) + .build(); + return this; + } + + public SignalWithStartWorkflowRequest build() { + return new SignalWithStartWorkflowRequest( + workflow, + args, + id, + taskQueue, + signal, + signalArgs, + executionTimeout, + runTimeout, + taskTimeout, + idReusePolicy, + idConflictPolicy, + retryPolicy, + cronSchedule, + memo, + searchAttributes, + priority, + versioningOverride, + startDelay, + userMetadata, + namespace == null + ? io.temporal.internal.nexus.system.TemporalModelConverters.workflowNamespace() + : namespace, + headers); + } + } + + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); + if (this.workflow != null) + proto.setWorkflowType( + io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto( + converter, (this.workflow))); + if (this.args != null) + proto.setInput( + converter + .toPayloads((this.args).toArray()) + .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + if (this.id != null) proto.setWorkflowId((this.id)); + if (this.taskQueue != null) + proto.setTaskQueue( + io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto( + converter, (this.taskQueue))); + if (this.signal != null) proto.setSignalName((this.signal)); + if (this.signalArgs != null) + proto.setSignalInput( + converter + .toPayloads((this.signalArgs).toArray()) + .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + if (this.executionTimeout != null) + proto.setWorkflowExecutionTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.executionTimeout))); + if (this.runTimeout != null) + proto.setWorkflowRunTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.runTimeout))); + if (this.taskTimeout != null) + proto.setWorkflowTaskTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.taskTimeout))); + if (this.idReusePolicy != null) + proto.setWorkflowIdReusePolicy( + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( + (this.idReusePolicy).getNumber())); + if (this.idConflictPolicy != null) + proto.setWorkflowIdConflictPolicy( + io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber( + (this.idConflictPolicy).getNumber())); + if (this.retryPolicy != null) + proto.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto( + converter, (this.retryPolicy))); + if (this.cronSchedule != null) proto.setCronSchedule((this.cronSchedule)); + if (this.memo != null) + proto.setMemo( + io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto( + converter, (this.memo))); + if (this.searchAttributes != null) + proto.setSearchAttributes( + io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto( + converter, (this.searchAttributes))); + if (this.priority != null) + proto.setPriority( + io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto( + converter, (this.priority))); + if (this.versioningOverride != null) + proto.setVersioningOverride( + io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto( + converter, (this.versioningOverride))); + if (this.startDelay != null) + proto.setWorkflowStartDelay( + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.startDelay))); + if (this.userMetadata != null) proto.setUserMetadata((this.userMetadata).toProto(converter)); + if (this.namespace != null) proto.setNamespace((this.namespace)); + if (this.headers != null) + proto.setHeader( + io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto( + converter, (this.headers))); + return proto.build(); + } + + public static SignalWithStartWorkflowRequest fromProto( + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { + Builder builder = SignalWithStartWorkflowRequest.newBuilder(); + builder.setWorkflow( + io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto( + converter, proto.getWorkflowType())); + if (proto.hasInput()) + builder.setArgs( + (java.util.List) + (Object) + io.temporal.workflow.NexgenRuntime.decodeSequence( + proto.getInput(), converter, Object.class, Object.class)); + builder.setId(proto.getWorkflowId()); + builder.setTaskQueue( + io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto( + converter, proto.getTaskQueue())); + builder.setSignal(proto.getSignalName()); + if (proto.hasSignalInput()) + builder.setSignalArgs( + (java.util.List) + (Object) + io.temporal.workflow.NexgenRuntime.decodeSequence( + proto.getSignalInput(), converter, Object.class, Object.class)); + if (proto.hasWorkflowExecutionTimeout()) + builder.setExecutionTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, proto.getWorkflowExecutionTimeout())); + if (proto.hasWorkflowRunTimeout()) + builder.setRunTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, proto.getWorkflowRunTimeout())); + if (proto.hasWorkflowTaskTimeout()) + builder.setTaskTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, proto.getWorkflowTaskTimeout())); + builder.setIdReusePolicy( + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( + (proto.getWorkflowIdReusePolicy()).getNumber())); + builder.setIdConflictPolicy( + io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber( + (proto.getWorkflowIdConflictPolicy()).getNumber())); + if (proto.hasRetryPolicy()) + builder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto( + converter, proto.getRetryPolicy())); + builder.setCronSchedule(proto.getCronSchedule()); + if (proto.hasMemo()) + builder.setMemo( + io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto( + converter, proto.getMemo())); + if (proto.hasSearchAttributes()) + builder.setSearchAttributes( + io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto( + converter, proto.getSearchAttributes())); + if (proto.hasPriority()) + builder.setPriority( + io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto( + converter, proto.getPriority())); + if (proto.hasVersioningOverride()) + builder.setVersioningOverride( + io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto( + converter, proto.getVersioningOverride())); + if (proto.hasWorkflowStartDelay()) + builder.setStartDelay( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, proto.getWorkflowStartDelay())); + if (proto.hasUserMetadata()) + builder.setUserMetadata( + io.temporal.workflow.UserMetadata.fromProto( + proto.getUserMetadata(), converter, io.temporal.workflow.UserMetadata.class)); + builder.setNamespace(proto.getNamespace()); + if (proto.hasHeader()) + builder.setHeaders( + io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto( + converter, proto.getHeader())); + return builder.build(); + } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter< + SignalWithStartWorkflowRequest> { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.class; + } + + public Object toTransferType(SignalWithStartWorkflowRequest value) { + return value == null + ? null + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); + } + + public SignalWithStartWorkflowRequest fromTransferType( + Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), + valueType); + } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java new file mode 100644 index 0000000000..a433bec3b8 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java @@ -0,0 +1,114 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Result of signaling a workflow and starting it if needed. */ +@io.temporal.common.converter.TransferTypeConvertible( + SignalWithStartWorkflowResponse.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SignalWithStartWorkflowResponse { + /** Run ID of the started workflow. */ + private final String runId; + + /** Whether the workflow was started. */ + private final Boolean started; + + @com.fasterxml.jackson.annotation.JsonCreator + public SignalWithStartWorkflowResponse( + @com.fasterxml.jackson.annotation.JsonProperty("runId") String runId, + @com.fasterxml.jackson.annotation.JsonProperty("started") Boolean started) { + this.runId = runId; + this.started = started; + } + + public String getRunId() { + return runId; + } + + public Boolean getStarted() { + return started; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(SignalWithStartWorkflowResponse value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private Builder() {} + + private Builder(SignalWithStartWorkflowResponse value) { + if (value == null) return; + this.runId = value.runId; + this.started = value.started; + } + + private String runId = null; + + public Builder setRunId(String value) { + this.runId = value; + return this; + } + + private Boolean started = null; + + public Builder setStarted(Boolean value) { + this.started = value; + return this; + } + + public SignalWithStartWorkflowResponse build() { + return new SignalWithStartWorkflowResponse(runId, started); + } + } + + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); + if (this.runId != null) proto.setRunId((this.runId)); + if (this.started != null) proto.setStarted((this.started)); + return proto.build(); + } + + public static SignalWithStartWorkflowResponse fromProto( + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { + Builder builder = SignalWithStartWorkflowResponse.newBuilder(); + builder.setRunId(proto.getRunId()); + builder.setStarted(proto.getStarted()); + return builder.build(); + } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter< + SignalWithStartWorkflowResponse> { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.class; + } + + public Object toTransferType(SignalWithStartWorkflowResponse value) { + return value == null + ? null + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); + } + + public SignalWithStartWorkflowResponse fromTransferType( + Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), + valueType); + } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java new file mode 100644 index 0000000000..19b7894340 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java @@ -0,0 +1,40 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Generated operation dispatch and serialization context acquisition. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SystemNexusOperations { + private SystemNexusOperations() {} + + public static + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput< + R> + execute( + SystemNexusWorkflowOutboundInterceptor interceptor, + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + R> + input) { + if ("temporal.api.workflowservice.v1.WorkflowService".equals(input.getService()) + && "SignalWithStartWorkflowExecution".equals(input.getOperation())) + return (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + R>) + interceptor.executeSignalWithStartWorkflow( + (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput) + input); + throw new IllegalArgumentException( + "Unsupported system Nexus operation: " + input.getService() + "/" + input.getOperation()); + } + + public static io.temporal.payload.context.SerializationContext serializationContext( + String service, String operation, Object request) { + if ("temporal.api.workflowservice.v1.WorkflowService".equals(service) + && "SignalWithStartWorkflowExecution".equals(operation)) + return io.temporal.internal.nexus.system.TemporalModelConverters + .signalWithStartWorkflowSerializationContext( + (io.temporal.workflow.SignalWithStartWorkflowRequest) request); + return null; + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java new file mode 100644 index 0000000000..f65d47a8b2 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java @@ -0,0 +1,41 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Generated typed system Nexus hooks. */ +public interface SystemNexusWorkflowOutboundInterceptor { + + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput< + R> + executeNexusOperation( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + R> + input); + + default io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + io.temporal.workflow.SignalWithStartWorkflowResponse> + executeSignalWithStartWorkflow( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + io.temporal.workflow.SignalWithStartWorkflowResponse> + input) { + return executeNexusOperation(input); + } + + abstract class Base implements SystemNexusWorkflowOutboundInterceptor { + protected abstract SystemNexusWorkflowOutboundInterceptor nextSystemNexusInterceptor(); + + @Override + public io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + io.temporal.workflow.SignalWithStartWorkflowResponse> + executeSignalWithStartWorkflow( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + io.temporal.workflow.SignalWithStartWorkflowResponse> + input) { + return nextSystemNexusInterceptor().executeSignalWithStartWorkflow(input); + } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java new file mode 100644 index 0000000000..5f46870136 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java @@ -0,0 +1,124 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Static metadata for a workflow execution. */ +@io.temporal.common.converter.TransferTypeConvertible(UserMetadata.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class UserMetadata { + /** + * Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be + * in single-line Temporal Markdown format. + */ + private final Object staticSummary; + + /** + * General fixed details for the workflow execution that may appear in UI and CLI. This can be in + * Temporal Markdown format and can span multiple lines. This value is fixed on the workflow + * execution and cannot be updated. + */ + private final Object staticDetails; + + @com.fasterxml.jackson.annotation.JsonCreator + public UserMetadata( + @com.fasterxml.jackson.annotation.JsonProperty("staticSummary") Object staticSummary, + @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") Object staticDetails) { + this.staticSummary = staticSummary; + this.staticDetails = staticDetails; + } + + public Object getStaticSummary() { + return staticSummary; + } + + public Object getStaticDetails() { + return staticDetails; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(UserMetadata value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private Builder() {} + + private Builder(UserMetadata value) { + if (value == null) return; + this.staticSummary = value.staticSummary; + this.staticDetails = value.staticDetails; + } + + private Object staticSummary = null; + + public Builder setStaticSummary(Object value) { + this.staticSummary = value; + return this; + } + + private Object staticDetails = null; + + public Builder setStaticDetails(Object value) { + this.staticDetails = value; + return this; + } + + public UserMetadata build() { + return new UserMetadata(staticSummary, staticDetails); + } + } + + public io.temporal.api.sdk.v1.UserMetadata toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.sdk.v1.UserMetadata.Builder proto = + io.temporal.api.sdk.v1.UserMetadata.newBuilder(); + if (this.staticSummary != null) + proto.setSummary(converter.toPayload((this.staticSummary)).get()); + if (this.staticDetails != null) + proto.setDetails(converter.toPayload((this.staticDetails)).get()); + return proto.build(); + } + + public static UserMetadata fromProto( + io.temporal.api.sdk.v1.UserMetadata proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { + Builder builder = UserMetadata.newBuilder(); + if (proto.hasSummary()) + builder.setStaticSummary( + (Object) converter.fromPayload(proto.getSummary(), Object.class, Object.class)); + if (proto.hasDetails()) + builder.setStaticDetails( + (Object) converter.fromPayload(proto.getDetails(), Object.class, Object.class)); + return builder.build(); + } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.sdk.v1.UserMetadata.class; + } + + public Object toTransferType(UserMetadata value) { + return value == null + ? null + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); + } + + public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.sdk.v1.UserMetadata) value, + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), + valueType); + } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java new file mode 100644 index 0000000000..64e487a6d8 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java @@ -0,0 +1,3029 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public abstract class WorkflowOperations { + protected WorkflowOperations() {} + + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + String workflow, + Object[] args, + String id, + String taskQueue, + String signal, + Object[] signalArgs) { + return signalWithStartWorkflow( + workflow, + args, + id, + taskQueue, + signal, + signalArgs, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** Signal a workflow, starting it first if needed. */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + String workflow, + Object[] args, + String id, + String taskQueue, + String signal, + Object[] signalArgs, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + requestBuilder.setArgs(java.util.Arrays.asList(java.util.Objects.requireNonNull(args, "args"))); + requestBuilder.setWorkflow(java.util.Objects.requireNonNull(workflow, "workflow")); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + requestBuilder.setSignalArgs( + java.util.Arrays.asList(java.util.Objects.requireNonNull(signalArgs, "signalArgs"))); + requestBuilder.setSignal(java.util.Objects.requireNonNull(signal, "signal")); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func3< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func3< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func3< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func3< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc3 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc3 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc3 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc3 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5, WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func5< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5, WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func5< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func5< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func5< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc5< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc5< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc5< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc5< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + static io.temporal.workflow.ExternalWorkflowStub executeSignalWithStartWorkflow( + io.temporal.workflow.SignalWithStartWorkflowRequest request) { + io.temporal.workflow.SignalWithStartWorkflowResponse result = + (io.temporal.workflow.SignalWithStartWorkflowResponse) + io.temporal.workflow.Workflow.newUntypedNexusServiceStub( + "temporal.api.workflowservice.v1.WorkflowService", + io.temporal.workflow.NexusServiceOptions.newBuilder() + .setEndpoint("__temporal_system") + .build()) + .execute( + "SignalWithStartWorkflowExecution", + io.temporal.workflow.SignalWithStartWorkflowResponse.class, + io.temporal.workflow.SignalWithStartWorkflowResponse.class, + request); + return io.temporal.workflow.Workflow.newUntypedExternalWorkflowStub( + io.temporal.api.common.v1.WorkflowExecution.newBuilder() + .setWorkflowId(request.getId()) + .setRunId(result.getRunId() == null ? "" : result.getRunId()) + .build()); + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java new file mode 100644 index 0000000000..5f341628fd --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java @@ -0,0 +1,9 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +@io.nexusrpc.Service(name = "temporal.api.workflowservice.v1.WorkflowService") +public interface WorkflowService { + @io.nexusrpc.Operation(name = "SignalWithStartWorkflowExecution") + io.temporal.workflow.SignalWithStartWorkflowResponse signalWithStartWorkflow( + io.temporal.workflow.SignalWithStartWorkflowRequest request); +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/system-nexus-roots.txt b/temporal-sdk/src/main/generated/io/temporal/workflow/system-nexus-roots.txt new file mode 100644 index 0000000000..434e51e32a --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/system-nexus-roots.txt @@ -0,0 +1,2 @@ +temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest +temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse diff --git a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java index a1b581a4e5..dcb9f450a4 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java +++ b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java @@ -37,7 +37,8 @@ * WorkflowInboundCallsInterceptor. */ @Experimental -public interface WorkflowOutboundCallsInterceptor { +public interface WorkflowOutboundCallsInterceptor + extends io.temporal.workflow.SystemNexusWorkflowOutboundInterceptor { final class ActivityInput { private final String activityName; diff --git a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java index 6f55f2f4ae..f03b3a7522 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java +++ b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java @@ -16,10 +16,17 @@ import java.util.function.Supplier; /** Convenience base class for WorkflowOutboundCallsInterceptor implementations. */ -public class WorkflowOutboundCallsInterceptorBase implements WorkflowOutboundCallsInterceptor { +public class WorkflowOutboundCallsInterceptorBase + extends io.temporal.workflow.SystemNexusWorkflowOutboundInterceptor.Base + implements WorkflowOutboundCallsInterceptor { private final WorkflowOutboundCallsInterceptor next; + @Override + protected WorkflowOutboundCallsInterceptor nextSystemNexusInterceptor() { + return next; + } + public WorkflowOutboundCallsInterceptorBase(WorkflowOutboundCallsInterceptor next) { this.next = next; } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java new file mode 100644 index 0000000000..7a420b642b --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java @@ -0,0 +1,105 @@ +package io.temporal.internal.nexus.system; + +import com.google.protobuf.Message; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.common.v1.Payloads; +import io.temporal.api.failure.v1.Failure; +import io.temporal.common.converter.DataConverter; +import io.temporal.common.converter.DataConverterException; +import io.temporal.common.converter.RawValue; +import io.temporal.internal.common.converter.TemporalTransferTypeDataConverter; +import io.temporal.internal.payload.visitor.SystemNexusPayloads; +import java.lang.reflect.Type; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import javax.annotation.Nonnull; + +/** Keeps the server-readable envelope separate from the destination workflow's user converter. */ +public final class SystemNexusDataConverter implements DataConverter { + public static final String ENDPOINT = "__temporal_system"; + private static final ThreadLocal USER_CONVERTER = new ThreadLocal<>(); + private final DataConverter userConverter; + + static DataConverter currentDataConverter() { + DataConverter converter = USER_CONVERTER.get(); + if (converter == null) + throw new IllegalStateException("System Nexus user converter context is not active"); + return converter; + } + + static T withDataConverter(DataConverter converter, Supplier action) { + Objects.requireNonNull(converter, "converter"); + DataConverter previous = USER_CONVERTER.get(); + USER_CONVERTER.set(converter); + try { + return action.get(); + } finally { + if (previous == null) USER_CONVERTER.remove(); + else USER_CONVERTER.set(previous); + } + } + + public SystemNexusDataConverter(DataConverter userConverter) { + this.userConverter = userConverter; + } + + @Override + public Optional toPayload(T value) { + if (value instanceof RawValue) return Optional.of(((RawValue) value).getPayload()); + return withDataConverter( + userConverter, + () -> { + Object transferred = TemporalTransferTypeDataConverter.toTransferValue(value); + if (!(transferred instanceof Message)) + throw new DataConverterException( + "System Nexus inputs must have a protobuf transfer type"); + return Optional.of(SystemNexusPayloads.pack((Message) transferred)); + }); + } + + @Override + public T fromPayload(Payload payload, Class valueClass, Type valueType) { + if (valueClass == RawValue.class) return valueClass.cast(new RawValue(payload)); + return withDataConverter( + userConverter, + () -> { + Message value = SystemNexusPayloads.unpack(payload).build(); + TemporalTransferTypeDataConverter.TransferType transfer = + TemporalTransferTypeDataConverter.transferTypeFor(valueClass, valueType); + if (transfer == null) return valueClass.cast(value); + if (!transfer.getRawType().isInstance(value)) + throw new DataConverterException( + "Unexpected system Nexus response type: " + + value.getDescriptorForType().getFullName()); + return transfer.fromValue(value, valueClass); + }); + } + + @Override + public Optional toPayloads(Object... values) { + if (values == null || values.length == 0) return Optional.empty(); + Payloads.Builder result = Payloads.newBuilder(); + for (Object value : values) result.addPayloads(toPayload(value).get()); + return Optional.of(result.build()); + } + + @Override + public T fromPayloads( + int index, Optional values, Class valueClass, Type valueType) { + if (!values.isPresent() || index >= values.get().getPayloadsCount()) return null; + return fromPayload(values.get().getPayloads(index), valueClass, valueType); + } + + @Nonnull + @Override + public RuntimeException failureToException(@Nonnull Failure failure) { + return userConverter.failureToException(failure); + } + + @Nonnull + @Override + public Failure exceptionToFailure(@Nonnull Throwable failure) { + return userConverter.exceptionToFailure(failure); + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java new file mode 100644 index 0000000000..6035f38fe1 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -0,0 +1,201 @@ +package io.temporal.internal.nexus.system; + +import io.temporal.api.common.v1.*; +import io.temporal.api.taskqueue.v1.TaskQueue; +import io.temporal.common.CronSchedule; +import io.temporal.common.MethodRetry; +import io.temporal.common.RetryOptions; +import io.temporal.common.VersioningOverride; +import io.temporal.common.converter.DataConverter; +import io.temporal.common.metadata.WorkflowMethodType; +import io.temporal.internal.common.*; +import io.temporal.internal.sync.ExternalWorkflowInvocationHandler; +import io.temporal.payload.context.WorkflowSerializationContext; +import io.temporal.workflow.Functions; +import io.temporal.workflow.SignalWithStartWorkflowRequest; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.BiConsumer; + +/** SDK-owned model conversion hooks used by the generated system Nexus bindings. */ +public final class TemporalModelConverters { + private TemporalModelConverters() {} + + /** Returns the user converter active during system Nexus transfer conversion. */ + public static DataConverter currentDataConverter() { + return SystemNexusDataConverter.currentDataConverter(); + } + + public static String workflowNamespace() { + return Workflow.getInfo().getNamespace(); + } + + /** Captures one typed workflow invocation without starting a child workflow. */ + public static ExternalWorkflowInvocationHandler.ProbeResult captureWorkflowCall( + Object method, Functions.Proc invocation, BiConsumer result) { + ExternalWorkflowInvocationHandler.ProbeResult call = + ExternalWorkflowInvocationHandler.probe(method, invocation, WorkflowMethodType.WORKFLOW); + result.accept(call.getName(), call.getArguments()); + return call; + } + + /** Captures one typed signal invocation without sending a signal. */ + public static void captureSignalCall( + Object method, Functions.Proc invocation, BiConsumer result) { + ExternalWorkflowInvocationHandler.ProbeResult call = + ExternalWorkflowInvocationHandler.probe(method, invocation, WorkflowMethodType.SIGNAL); + result.accept(call.getName(), call.getArguments()); + } + + /** Merges the original method annotation with explicit retry settings. */ + public static RetryOptions mergeMethodRetry( + ExternalWorkflowInvocationHandler.ProbeResult call, RetryOptions explicit) { + return RetryOptions.merge(call.getMethod().getAnnotation(MethodRetry.class), explicit); + } + + /** Explicit schedules, including an empty string, override the method annotation. */ + public static String mergeCronSchedule( + ExternalWorkflowInvocationHandler.ProbeResult call, String explicit) { + CronSchedule annotation = call.getMethod().getAnnotation(CronSchedule.class); + return OptionsUtils.merge(annotation == null ? "" : annotation.value(), explicit, String.class); + } + + public static WorkflowSerializationContext signalWithStartWorkflowSerializationContext( + SignalWithStartWorkflowRequest request) { + return new WorkflowSerializationContext(request.getNamespace(), request.getId()); + } + + public static RuntimeException failureFromProto( + DataConverter converter, io.temporal.api.failure.v1.Failure value) { + return converter.failureToException(value); + } + + public static io.temporal.api.failure.v1.Failure failureToProto( + DataConverter converter, RuntimeException value) { + return converter.exceptionToFailure(value); + } + + public static WorkflowType workflowTypeToProto(DataConverter converter, String value) { + return WorkflowType.newBuilder().setName(value).build(); + } + + public static String workflowTypeFromProto(DataConverter converter, WorkflowType value) { + return value.getName(); + } + + public static TaskQueue taskQueueToProto(DataConverter converter, String value) { + return TaskQueue.newBuilder().setName(value).build(); + } + + public static String taskQueueFromProto(DataConverter converter, TaskQueue value) { + return value.getName(); + } + + public static com.google.protobuf.Duration durationToProto( + DataConverter converter, Duration value) { + return ProtobufTimeUtils.toProtoDuration(value); + } + + public static Duration durationFromProto( + DataConverter converter, com.google.protobuf.Duration value) { + return ProtobufTimeUtils.toJavaDuration(value); + } + + public static RetryPolicy retryPolicyToProto(DataConverter converter, RetryOptions value) { + return RetryOptionsUtils.toRetryPolicy(value).build(); + } + + public static RetryOptions retryPolicyFromProto(DataConverter converter, RetryPolicy value) { + return RetryOptionsUtils.toRetryOptions(value); + } + + public static Memo memoToProto(DataConverter converter, Map value) { + return Memo.newBuilder().putAllFields(HeaderUtils.intoPayloadMap(converter, value)).build(); + } + + public static Map memoFromProto(DataConverter converter, Memo value) { + Map result = new LinkedHashMap<>(); + value + .getFieldsMap() + .forEach( + (key, payload) -> + result.put(key, converter.fromPayload(payload, Object.class, Object.class))); + return result; + } + + public static Header headerToProto(DataConverter converter, Map value) { + Header.Builder builder = Header.newBuilder(); + value.forEach( + (key, payload) -> + builder.putFields( + key, + converter.toPayload(new io.temporal.common.converter.RawValue(payload)).get())); + return builder.build(); + } + + public static Map headerFromProto(DataConverter converter, Header value) { + Map result = new LinkedHashMap<>(); + value + .getFieldsMap() + .forEach( + (key, payload) -> + result.put( + key, + converter + .fromPayload( + payload, + io.temporal.common.converter.RawValue.class, + io.temporal.common.converter.RawValue.class) + .getPayload())); + return result; + } + + public static io.temporal.api.common.v1.SearchAttributes searchAttributesToProto( + DataConverter converter, io.temporal.common.SearchAttributes value) { + return SearchAttributesUtil.encodeTyped(value); + } + + public static io.temporal.common.SearchAttributes searchAttributesFromProto( + DataConverter converter, io.temporal.api.common.v1.SearchAttributes value) { + return SearchAttributesUtil.decodeTyped(value); + } + + public static Priority priorityToProto( + DataConverter converter, io.temporal.common.Priority value) { + return ProtoConverters.toProto(value); + } + + public static io.temporal.common.Priority priorityFromProto( + DataConverter converter, Priority value) { + return ProtoConverters.fromProto(value); + } + + public static io.temporal.api.workflow.v1.VersioningOverride versioningOverrideToProto( + DataConverter converter, VersioningOverride value) { + return ProtoConverters.toProto(value); + } + + @SuppressWarnings("deprecation") + public static VersioningOverride versioningOverrideFromProto( + DataConverter converter, io.temporal.api.workflow.v1.VersioningOverride value) { + if (value.hasOneTime() && value.getOneTime().hasTargetDeploymentVersion()) + return new VersioningOverride.OneTimeVersioningOverride( + deployment(value.getOneTime().getTargetDeploymentVersion())); + if (value.hasPinned() && value.getPinned().hasVersion()) + return new VersioningOverride.PinnedVersioningOverride( + deployment(value.getPinned().getVersion())); + if (!value.getPinnedVersion().isEmpty()) + return new VersioningOverride.PinnedVersioningOverride( + io.temporal.common.WorkerDeploymentVersion.fromCanonicalString(value.getPinnedVersion())); + if (value.getAutoUpgrade()) return new VersioningOverride.AutoUpgradeVersioningOverride(); + throw new IllegalArgumentException("Unknown versioning override proto shape"); + } + + private static io.temporal.common.WorkerDeploymentVersion deployment( + io.temporal.api.deployment.v1.WorkerDeploymentVersion value) { + return new io.temporal.common.WorkerDeploymentVersion( + value.getDeploymentName(), value.getBuildId()); + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java index 0f7def87ea..5469a2ce12 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java @@ -4,13 +4,111 @@ import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata; import io.temporal.common.metadata.POJOWorkflowMethodMetadata; +import io.temporal.common.metadata.WorkflowMethodType; +import io.temporal.internal.common.InternalUtils; +import io.temporal.internal.common.JavaLambdaUtils; import io.temporal.workflow.ExternalWorkflowStub; import io.temporal.workflow.Functions; +import java.lang.invoke.MethodHandleInfo; +import java.lang.invoke.SerializedLambda; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.util.Objects; -/** Dynamic implementation of a strongly typed child workflow interface. */ -class ExternalWorkflowInvocationHandler implements InvocationHandler { +/** Dynamic implementation of a strongly typed external workflow interface. */ +public class ExternalWorkflowInvocationHandler implements InvocationHandler { + + private static final ThreadLocal probeContext = new ThreadLocal<>(); + private static final ThreadLocal probeResult = new ThreadLocal<>(); + + /** Probes one invocation without starting a workflow or sending a signal. */ + public static ProbeResult probe( + Object method, Functions.Proc invocation, WorkflowMethodType expected) { + Objects.requireNonNull(invocation, "invocation"); + if (probeContext.get() != null) { + throw new IllegalStateException("Already probing an external workflow invocation"); + } + SerializedLambda reference = + JavaLambdaUtils.toSerializedLambda(Objects.requireNonNull(method, "method")); + Object target = JavaLambdaUtils.getTarget(reference); + if (reference == null + || reference.getImplMethodKind() != MethodHandleInfo.REF_invokeInterface + || target == null + || !Proxy.isProxyClass(target.getClass()) + || !(Proxy.getInvocationHandler(target) instanceof ExternalWorkflowInvocationHandler)) { + throw new IllegalArgumentException( + "Expected a bound method from Workflow.newExternalWorkflowStub"); + } + ProbeContext context = new ProbeContext(expected); + probeContext.set(context); + try { + invocation.apply(); + ProbeResult result = probeResult.get(); + if (context.invocations != 1 || result == null) { + throw new IllegalArgumentException( + "Expected exactly one external workflow " + expected + " invocation"); + } + return result; + } finally { + probeResult.remove(); + probeContext.remove(); + } + } + + private static final class ProbeContext { + private final WorkflowMethodType expected; + private int invocations; + + private ProbeContext(WorkflowMethodType expected) { + this.expected = Objects.requireNonNull(expected, "expected"); + } + } + + /** Metadata captured from a bound external workflow method. */ + public static final class ProbeResult { + private final ExternalWorkflowStub stub; + private final String name; + private final Object[] arguments; + private final Class resultClass; + private final Type resultType; + private final Method method; + + private ProbeResult( + ExternalWorkflowStub stub, POJOWorkflowMethodMetadata metadata, Object[] args) { + this.stub = stub; + this.name = metadata.getName(); + this.arguments = args == null ? new Object[0] : args.clone(); + this.method = metadata.getWorkflowMethod(); + this.resultClass = method.getReturnType(); + this.resultType = method.getGenericReturnType(); + } + + public ExternalWorkflowStub getStub() { + return stub; + } + + public String getName() { + return name; + } + + public Object[] getArguments() { + return arguments.clone(); + } + + public Class getResultClass() { + return resultClass; + } + + public Type getResultType() { + return resultType; + } + + public Method getMethod() { + return method; + } + } private final ExternalWorkflowStub stub; private final POJOWorkflowInterfaceMetadata workflowMetadata; @@ -40,6 +138,15 @@ public Object invoke(Object proxy, Method method, Object[] args) { return stub; } POJOWorkflowMethodMetadata methodMetadata = workflowMetadata.getMethodMetadata(method); + ProbeContext context = probeContext.get(); + if (context != null) { + if (++context.invocations != 1 || methodMetadata.getType() != context.expected) { + throw new IllegalArgumentException( + "Expected exactly one external workflow " + context.expected + " invocation"); + } + probeResult.set(new ProbeResult(stub, methodMetadata, args)); + return InternalUtils.getValueOrDefault(null, method.getReturnType()); + } switch (methodMetadata.getType()) { case QUERY: throw new UnsupportedOperationException( diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java index 821b92f075..7e80782373 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java @@ -61,7 +61,7 @@ public Promise executeAsync( .mergeNexusOperationOptions(options.getOperationMethodOptions().get(operationName)) .build(); WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput result = - outboundCallsInterceptor.executeNexusOperation( + executeNexusOperation( new WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput<>( options.getEndpoint(), name, @@ -88,7 +88,7 @@ public NexusOperationHandle start( .mergeNexusOperationOptions(options.getOperationMethodOptions().get(operationName)) .build(); WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput result = - outboundCallsInterceptor.executeNexusOperation( + executeNexusOperation( new WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput<>( options.getEndpoint(), name, @@ -101,6 +101,15 @@ public NexusOperationHandle start( return new NexusOperationHandleImpl<>(result.getOperationExecution(), result.getResult()); } + private WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput executeNexusOperation( + WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { + if (io.temporal.internal.nexus.system.SystemNexusDataConverter.ENDPOINT.equals( + input.getEndpoint())) { + return io.temporal.workflow.SystemNexusOperations.execute(outboundCallsInterceptor, input); + } + return outboundCallsInterceptor.executeNexusOperation(input); + } + @Override public NexusServiceOptions getOptions() { return options; diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java index 2d5cfcba33..a7eff474d2 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java @@ -828,10 +828,24 @@ public ExecuteNexusOperationOutput executeNexusOperation( // contextualized by the endpoint, service and operation instead. The same converter decodes the // result and converts failures, so each operation keeps the converter selected for it even when // several operations are in flight at once. - DataConverter nexusDataConverter = - dataConverter.withContext( - new NexusSerializationContext( - input.getEndpoint(), input.getService(), input.getOperation())); + final DataConverter nexusDataConverter; + final DataConverter userMetadataDataConverter; + if (io.temporal.internal.nexus.system.SystemNexusDataConverter.ENDPOINT.equals( + input.getEndpoint())) { + io.temporal.payload.context.SerializationContext context = + io.temporal.workflow.SystemNexusOperations.serializationContext( + input.getService(), input.getOperation(), input.getArg()); + userMetadataDataConverter = + context == null ? dataConverter : dataConverter.withContext(context); + nexusDataConverter = + new io.temporal.internal.nexus.system.SystemNexusDataConverter(userMetadataDataConverter); + } else { + nexusDataConverter = + dataConverter.withContext( + new NexusSerializationContext( + input.getEndpoint(), input.getService(), input.getOperation())); + userMetadataDataConverter = nexusDataConverter; + } Optional payload = nexusDataConverter.toPayload(input.getArg()); @@ -852,7 +866,7 @@ public ExecuteNexusOperationOutput executeNexusOperation( @Nullable UserMetadata userMetadata = - makeUserMetaData(input.getOptions().getSummary(), null, nexusDataConverter); + makeUserMetaData(input.getOptions().getSummary(), null, userMetadataDataConverter); StartNexusOperationParameters parameters = new StartNexusOperationParameters( diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java b/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java index 5f1c1f86f6..2e77b94081 100644 --- a/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java +++ b/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java @@ -53,7 +53,7 @@ * * @see io.temporal.workflow */ -public final class Workflow { +public final class Workflow extends WorkflowOperations { public static final int DEFAULT_VERSION = WorkflowInternal.DEFAULT_VERSION; /** diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md new file mode 100644 index 0000000000..54c3165b2c --- /dev/null +++ b/temporal-sdk/src/main/nexus/README.md @@ -0,0 +1,57 @@ +# System Nexus bindings + +The WIT definitions here are a temporary copy of the shared multi-language +definitions in nex-gen's `advanced/samples/inputs/workflow-service.wit` and +`deps/nexus-temporal-types/model.wit`. Keep the copies identical; Java directives +belong in the shared source alongside the other languages. The SDK will +eventually consume these definitions from the API repo instead. Protobuf +descriptors from +`temporal-serviceclient:generateProto` validate the mappings during generation. + +Regenerate with nex-gen 0.2.9 built with its `advanced` feature: + +```sh +./gradlew :temporal-sdk:generateNexusSystemApi \ + -PnexgenBinary=/path/to/nexgen +./gradlew --offline spotlessApply +``` + +Generated Java and `system-nexus-roots.txt` are checked in under +`src/main/generated/io/temporal/workflow`, an isolated main Java source root. +The generator uses `--package-name io.temporal.workflow` and the WIT annotation +`@nexus.operations-class java="WorkflowOperations"`. `Workflow` extends this +generated base once; additional operations require no handwritten facade methods. +Generated operations take required fields as parameters and optional fields in +generated options builders, all available from the workflow package. +Typed overloads take bound methods followed directly by arguments. SDK-owned +call-extractor hooks resolve annotated workflow/signal names and arguments +without executing commands; the generated wrapper constructs the request. +Primary callable arities zero through six and other callable arities zero or one +come from Java rendering policy and the IDL's primary marker. No operation names +or composite-operation roles are encoded in the generator. Java-only +`merge-from-function` hooks declare retry and cron merging from the workflow +method's original annotations. The generator retains raw probe metadata, and +SDK helpers apply normal client precedence without synthesizing `WorkflowOptions`. +Explicit ID/task queue and other options remain independent of stub metadata. +The manifest derives from operation input/output protobuf transfer types. The service client's Java +payload visitor generator consumes it, including payload-free response roots, +without depending on compiled SDK classes. + +Regeneration passes `--format` to nex-gen, which uses google-java-format 1.24.0 +to match the SDK's Spotless configuration. Nex-gen downloads and caches its +standalone JAR on first use; for offline regeneration, set +`NEXGEN_JAVA_FORMAT_JAR` to a local all-dependencies JAR. A JDK must be on `PATH`. + +`TemporalModelConverters` contains the SDK-owned conversion helpers. The emitted +`NexgenRuntime` contains only payload-sequence decoding. Converter scoping lives +in `SystemNexusDataConverter`; generated transfer converters obtain the active +converter through `TemporalModelConverters.currentDataConverter()` and fail +when no scope is active, matching Python. Protobuf field access is generated +directly. Nex-gen assembles the required runtime helpers from Rust strings. +Normal Java SDK builds do not require Rust or nex-gen. + +The SDK wraps any configured `DataConverter` in `SystemNexusDataConverter` for +system operations. That wrapper handles the outer envelope and delegates nested +user conversion; custom converters do not need to recognize system envelopes. +The shared payload visitor descends into marked envelopes for payload traversal. +`CodecDataConverter` contains no system Nexus handling. diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md new file mode 100644 index 0000000000..e550dd3927 --- /dev/null +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -0,0 +1,85 @@ +# Signal with start inside workflows + +The generated workflow API atomically signals an external workflow, starting it +when necessary. It requires a server supporting the system workflow service. + +```java +ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( + "TargetWorkflow", new Object[] {input}, "target", "target-queue", + "notify", new Object[] {signal}, + SignalWithStartWorkflowOptions.newBuilder() + .setRunTimeout(timeout) + .build()); +``` + +Import `Workflow`, `SignalWithStartWorkflowOptions`, and `ExternalWorkflowStub` +from `io.temporal.workflow`. The generated options builder contains the API's +options, including timeouts, retry policy, memo, conflict policy, and flattened +static summary/details setters. Workflow type, argument array, ID, task queue, signal name, and signal argument array +are required parameters. An overload without options uses defaults. The request +is constructed internally. Namespace defaults to the caller's namespace. Request ID is omitted: +the system service manages it. + +The call returns after signal delivery/start completes. The returned external +stub supports further signals and cancellation. Use +`Async.function(() -> Workflow.signalWithStartWorkflow(workflowType, args, +workflowId, taskQueue, signalName, signalArgs, options))` for a promise. + +The typed overload checks workflow and signal arguments against their interface: + +```java +ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( + target::run, input, "target", "target-queue", + target::notifySignal, signal, + SignalWithStartWorkflowOptions.newBuilder().setRunTimeout(timeout).build()); +``` + +Create `target` with `Workflow.newExternalWorkflowStub(TargetWorkflow.class, "target")`. +Pass bound workflow and signal methods followed directly by their arguments. +Typed overloads cover zero through six workflow arguments and zero or one signal +argument, including void workflow methods. Other arities use the name-based API. +The compiler checks arguments and retains generic workflow result information in +the functional interface. The operation itself returns an external stub, not the +workflow result. + +The existing external invocation handler probes method names, arguments, result +types, target execution, and the original annotated method using scoped +thread locals. It sends no commands while probing and restores normal invocation +behavior afterward, including on failure. Query/update methods and receiver +lambdas are rejected. Both APIs take invocation arguments directly; options do +not contain argument fields. +Both forms support `Async.function` and an overload omitting options. + +Typed calls merge the workflow method's `@MethodRetry` and `@CronSchedule` with +explicit retry/cron options, matching the client SDK. Retry fields use +`RetryOptions.merge(annotation, explicitOptions)`; explicit non-default settings +take precedence over annotation values. Cron uses the annotation when the +explicit value is null; an explicit empty string disables the annotated schedule. +The signal method's annotations are not used for these fields. Defaults apply +with null or omitted options. Untyped calls have no method annotations to merge. + +The shared WIT declares `@nexus.merge-from-function function="workflow"` hooks +on the retry and cron fields. Java generation retains the function's raw probe +metadata and calls the selected SDK merge helpers, without synthesizing +`WorkflowOptions` or hardcoding retry/cron policy in the generator. This directive +currently affects Java only. + +Workflow ID and task queue remain explicit. Relationships between workflow and +signal references are not declared and cross-reference constraints remain +deferred. Other options use their explicit values and existing defaults. + +`Workflow` inherits generated operations from `WorkflowOperations`. New WIT +operations become available after regeneration, without adding handwritten +options, capture proxies, stubs, or facade methods. The output transform, request +fields, and serialization-context hook are declared in WIT. The converter uses +the destination namespace and workflow ID for nested payloads, codecs, and +failures; the outer system envelope remains server-readable. + +`SystemSignalWithStartIntegrationTest` verifies this converter selection against a +supporting server with a signing codec, overlapping calls to distinct destination +workflows, payload inspection in history, and replay. Converter unit tests cover +valid and unknown versioning override shapes; unknown shapes are rejected. + +This operation serializes the request and deserializes a response with no user +payloads. Future operations returning embedded payloads must use generic response +models and propagate concrete result types from the API to transfer conversion. diff --git a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit new file mode 100644 index 0000000000..606431dd9c --- /dev/null +++ b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit @@ -0,0 +1,254 @@ +package nexus:temporal-types@1.0.0; + +interface model { + /// String-shaped placeholder for semantic types that generators reinterpret. + type placeholder = string; + + /// @nexus.proto "temporal.api.common.v1.Payload" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="Object" + /// python="typing.Any" + /// typescript="common.Payload" + /// go="any" + /// dotnet="object?" + /// dotnet-from="ProtoExtensions.FromPayload" + /// dotnet-to="ProtoExtensions.ToPayload" + /// typescript-import="@temporalio/common" + type payload = placeholder; + + /// @nexus.proto "temporal.api.common.v1.Payloads" + /// typescript-import="@temporalio/proto" + /// @nexus.type + /// java="java.util.List" + /// go="[]any" + /// dotnet="IReadOnlyCollection" + /// dotnet-from="ProtoExtensions.FromPayloads" + /// dotnet-to="ProtoExtensions.ToPayloads" + type payloads = list; + + /// Temporal failure represented by the target SDK's native exception/error type. + /// The SDK failure converter owns the recursive cause and failure-info structure. + /// @nexus.proto "temporal.api.failure.v1.Failure" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="RuntimeException" + /// java-from="failureFromProto" + /// java-to="failureToProto" + /// python="BaseException" + /// typescript="Error" + /// go="error" + /// dotnet="System.Exception" + /// dotnet-from="ProtoExtensions.FromFailureProto" + /// dotnet-to="ProtoExtensions.ToFailureProto" + type failure = placeholder; + + /// Callable result annotation for workflow functions. + /// @nexus.type + /// python="collections.abc.Awaitable[WorkflowResult]" + /// typescript="Promise" + /// go="any" + /// dotnet="System.Threading.Tasks.Task" + type workflow-result = placeholder; + + /// Receiver/context argument for workflow callable method forms. + /// @nexus.type python="typing.Any" typescript="any" go="go.temporal.io/sdk/workflow:workflow.Context" dotnet="object" + type callable-prefix = placeholder; + + /// @nexus.function-args + /// varargs=true + /// param="args" + /// typescript-drop-prefix=true + workflow-call: async func(callable-prefix: callable-prefix, args: payloads) -> workflow-result; + + /// Callable result annotation for signal functions. + /// @nexus.type java="Void" python="None | collections.abc.Awaitable[None]" typescript="void" go="any" dotnet="void" + type signal-result = placeholder; + + /// @nexus.function-args + /// varargs=true + /// param="signal-args" + /// typescript-drop-prefix=true + signal-call: func(callable-prefix: callable-prefix, signal-args: payloads) -> signal-result; + + /// @nexus.proto "temporal.api.common.v1.WorkflowType" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="String" + /// java-from="workflowTypeFromProto" + /// java-to="workflowTypeToProto" + /// python="str" + /// typescript="string" + /// go="string" + /// dotnet="string" + /// dotnet-from="ProtoExtensions.FromWorkflowTypeProto" + /// dotnet-to="ProtoExtensions.ToWorkflowTypeProto" + type workflow-type = placeholder; + + /// @nexus.function + /// primary=true + /// signature="workflow-call" + /// args-field="input" + /// result-type-parameter="WorkflowResult" + /// alternate-type="workflow-type" + /// go-name-extractor="WorkflowFunctionName" + /// dotnet-name-extractor="TemporalFunctionNames.WorkflowName" + /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" + /// java-call-extractor="captureWorkflowCall" + /// java-call-metadata-type="io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult" + /// @nexus.add-rpc-compatible-with "workflow-type" + type workflow-function = placeholder; + + /// @nexus.function + /// signature="signal-call" + /// args-field="signal-input" + /// alternate-type="string" + /// go-value-type="string" + /// go-args-type="any" + /// python-converter="signal_function_to_proto" + /// typescript-name-extractor="signalFunctionName" + /// dotnet-name-extractor="TemporalFunctionNames.SignalName" + /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" + /// java-call-extractor="captureSignalCall" + /// typescript-value-type="common.SignalDefinition" + /// typescript-args-type="Value extends common.SignalDefinition ? Args : never" + /// typescript-import="@temporalio/common" + /// @nexus.add-rpc-compatible-with "string" + type signal-function = placeholder; + + /// @nexus.proto "temporal.api.common.v1.RetryPolicy" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.common.RetryOptions" + /// java-from="retryPolicyFromProto" + /// java-to="retryPolicyToProto" + /// python="temporalio.common.RetryPolicy" + /// typescript="common.RetryPolicy" + /// go="go.temporal.io/sdk/temporal.RetryPolicy" + /// dotnet="Temporalio.Common.RetryPolicy" + /// dotnet-from="ProtoExtensions.FromRetryPolicyProto" + /// typescript-import="@temporalio/common" + type retry-policy = placeholder; + + /// @nexus.proto "temporal.api.taskqueue.v1.TaskQueue" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="String" + /// java-from="taskQueueFromProto" + /// java-to="taskQueueToProto" + /// python="str" + /// typescript="string" + /// go="string" + /// dotnet="string" + /// dotnet-from="ProtoExtensions.FromTaskQueueProto" + /// dotnet-to="ProtoExtensions.ToTaskQueueProto" + type task-queue = placeholder; + + /// @nexus.proto "temporal.api.common.v1.Memo" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="java.util.Map" + /// java-from="memoFromProto" + /// java-to="memoToProto" + /// python="collections.abc.Mapping[str, typing.Any]" + /// typescript="Record" + /// go="map[string]any" + /// dotnet="IReadOnlyDictionary" + /// dotnet-from="ProtoExtensions.FromMemoProto" + type memo = placeholder; + + /// @nexus.proto "temporal.api.common.v1.Header" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="java.util.Map" + /// java-from="headerFromProto" + /// java-to="headerToProto" + /// python="collections.abc.Mapping[str, typing.Any]" + /// typescript="common.Headers" + /// go="map[string]any" + /// dotnet="IReadOnlyDictionary" + /// dotnet-from="ProtoExtensions.FromHeaderProto" + /// dotnet-to="ProtoExtensions.ToHeaderProto" + /// typescript-import="@temporalio/common" + type header = placeholder; + + /// @nexus.proto "temporal.api.common.v1.SearchAttributes" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.common.SearchAttributes" + /// java-from="searchAttributesFromProto" + /// java-to="searchAttributesToProto" + /// python="temporalio.common.TypedSearchAttributes" + /// typescript="common.TypedSearchAttributes" + /// go="go.temporal.io/sdk/temporal.SearchAttributes" + /// dotnet="Temporalio.Common.SearchAttributeCollection" + /// dotnet-from="ProtoExtensions.FromSearchAttributesProto" + /// typescript-import="@temporalio/common" + type search-attributes = placeholder; + + /// @nexus.proto "temporal.api.common.v1.Priority" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.common.Priority" + /// java-from="priorityFromProto" + /// java-to="priorityToProto" + /// python="temporalio.common.Priority" + /// typescript="common.Priority" + /// go="go.temporal.io/sdk/temporal.Priority" + /// dotnet="Temporalio.Common.Priority" + /// dotnet-from="ProtoExtensions.FromPriorityProto" + /// typescript-import="@temporalio/common" + type priority = placeholder; + + /// @nexus.proto "temporal.api.workflow.v1.VersioningOverride" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.common.VersioningOverride" + /// java-from="versioningOverrideFromProto" + /// java-to="versioningOverrideToProto" + /// python="temporalio.common.VersioningOverride" + /// typescript="common.VersioningOverride" + /// go="go.temporal.io/sdk/client.VersioningOverride" + /// dotnet="Temporalio.Common.VersioningOverride" + /// dotnet-from="ProtoExtensions.FromVersioningOverrideProto" + /// typescript-import="@temporalio/common" + type versioning-override = placeholder; + + /// @nexus.proto "google.protobuf.Duration" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="java.time.Duration" + /// java-from="durationFromProto" + /// java-to="durationToProto" + /// python="datetime.timedelta" + /// typescript="common.Duration" + /// go="time.Duration" + /// dotnet="System.TimeSpan" + /// dotnet-from="ProtoExtensions.FromDurationProto" + /// typescript-import="@temporalio/common" + type duration = placeholder; + + /// @nexus.proto "temporal.api.enums.v1.WorkflowIdReusePolicy" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.api.enums.v1.WorkflowIdReusePolicy" + /// python="temporalio.common.WorkflowIDReusePolicy" + /// typescript="common.WorkflowIdReusePolicy" + /// go="go.temporal.io/api/enums/v1:enums.WorkflowIdReusePolicy" + /// dotnet="Temporalio.Api.Enums.V1.WorkflowIdReusePolicy" + /// typescript-import="@temporalio/common" + type workflow-id-reuse-policy = placeholder; + + /// @nexus.proto "temporal.api.enums.v1.WorkflowIdConflictPolicy" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.api.enums.v1.WorkflowIdConflictPolicy" + /// python="temporalio.common.WorkflowIDConflictPolicy" + /// typescript="common.WorkflowIdConflictPolicy" + /// go="go.temporal.io/api/enums/v1:enums.WorkflowIdConflictPolicy" + /// dotnet="Temporalio.Api.Enums.V1.WorkflowIdConflictPolicy" + /// typescript-import="@temporalio/common" + type workflow-id-conflict-policy = placeholder; + + /// @nexus.doc "Static metadata for a workflow execution." + /// @nexus.proto "temporal.api.sdk.v1.UserMetadata" typescript-import="@temporalio/proto" + /// @nexus.flatten-in-api + /// @nexus.experimental + record user-metadata { + /// @nexus.doc "Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be in single-line Temporal Markdown format." + /// @nexus.proto-field "summary" + /// @nexus.flattened-type java="String" python="str" typescript="string" dotnet="string" go="string" + static-summary: option, + /// @nexus.doc "General fixed details for the workflow execution that may appear in UI and CLI. This can be in Temporal Markdown format and can span multiple lines. This value is fixed on the workflow execution and cannot be updated." + /// @nexus.proto-field "details" + /// @nexus.flattened-type java="String" python="str" typescript="string" dotnet="string" go="string" + static-details: option, + } +} diff --git a/temporal-sdk/src/main/nexus/workflow-service.wit b/temporal-sdk/src/main/nexus/workflow-service.wit new file mode 100644 index 0000000000..88b821fa8b --- /dev/null +++ b/temporal-sdk/src/main/nexus/workflow-service.wit @@ -0,0 +1,149 @@ +package temporal:nexus@1.0.0; + +world system { + export workflow-service; +} + +/// @nexus.endpoint "temporal-system" go="__temporal_system" python="__temporal_system" java="__temporal_system" +/// @nexus.service-name "temporal.api.workflowservice.v1.WorkflowService" +/// @nexus.operations-class java="WorkflowOperations" +/// @nexus.delay-load-temporalio-workflow +/// @nexus.experimental +interface workflow-service { + use nexus:temporal-types/model@1.0.0.{ + duration, + header, + memo, + payloads, + placeholder, + priority, + retry-policy, + search-attributes, + signal-function, + task-queue, + user-metadata, + versioning-override, + workflow-function, + workflow-id-conflict-policy, + workflow-id-reuse-policy, + }; + + /// @nexus.doc "Request fields for signaling a workflow, starting it first if needed." + /// @nexus.experimental + /// @nexus.proto "temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest" typescript-import="@temporalio/proto" + record signal-with-start-workflow-request { + /// @nexus.doc + /// python="Workflow type name or callable identifying the workflow to start." + /// typescript="Workflow type name or workflow function identifying the workflow to start." + /// dotnet="Workflow type name or workflow expression identifying the workflow to start." + /// go="Workflow function identifying the workflow to start." + /// @nexus.proto-field "workflow_type" + workflow: workflow-function, + /// @nexus.doc "Unique identifier for the workflow execution. Must be nonempty." + /// @nexus.proto-field "workflow_id" + id: string, + /// @nexus.doc "Task queue to run the workflow on." + task-queue: task-queue, + /// @nexus.doc + /// python="Signal name or callable to send with the start request." + /// typescript="Signal name or signal definition to send with the start request." + /// dotnet="Signal name or signal expression to send with the start request." + /// go="Signal name to send with the start request." + /// @nexus.proto-field "signal_name" + signal: signal-function, + /// @nexus.doc "Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited." + /// @nexus.proto-field "workflow_execution_timeout" + /// @nexus.name go="WorkflowExecutionTimeout" + execution-timeout: option, + /// @nexus.doc "Timeout of a single workflow run. Defaults to the workflow execution timeout." + /// @nexus.proto-field "workflow_run_timeout" + /// @nexus.name go="WorkflowRunTimeout" + run-timeout: option, + /// @nexus.doc "Timeout of a single workflow task. Defaults to 10 seconds." + /// @nexus.proto-field "workflow_task_timeout" + /// @nexus.name go="WorkflowTaskTimeout" + task-timeout: option, + /// @nexus.omit + identity: placeholder, + /// @nexus.omit + request-id: placeholder, + /// @nexus.doc "Behavior when a closed workflow with the same ID exists. Default is allow-duplicate." + /// @nexus.proto-field "workflow_id_reuse_policy" + /// @nexus.default "allow-duplicate" + /// @nexus.name go="WorkflowIDReusePolicy" + id-reuse-policy: workflow-id-reuse-policy, + /// @nexus.doc "Behavior when a workflow is currently running with the same ID. Set to use-existing for idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is terminate-if-running. Defaults to use-existing." + /// @nexus.proto-field "workflow_id_conflict_policy" + /// @nexus.name go="WorkflowIDConflictPolicy" + id-conflict-policy: option, + /// @nexus.doc "Retry policy for the workflow." + /// @nexus.merge-from-function function="workflow" java="mergeMethodRetry" + retry-policy: option, + /// @nexus.doc "Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job." + /// @nexus.merge-from-function function="workflow" java="mergeCronSchedule" + cron-schedule: option, + /// @nexus.doc "Memo for the workflow." + memo: option, + /// @nexus.doc "Typed search attributes for the workflow." + /// @nexus.name go="TypedSearchAttributes" + search-attributes: option, + /// @nexus.doc "Priority of the workflow execution." + priority: option, + /// @nexus.doc "Override for workflow versioning behavior." + versioning-override: option, + /// @nexus.doc "Amount of time to wait before starting the workflow. This does not work with cron-schedule." + /// @nexus.proto-field "workflow_start_delay" + start-delay: option, + /// @nexus.doc "Static metadata for the workflow execution." + user-metadata: option, + /// @nexus.source java="workflowNamespace()" python="workflow_namespace()" typescript="workflowNamespace()" go="WorkflowNamespace(ctx)" dotnet="TemporalWorkflowContext.WorkflowNamespace()" + /// @nexus.doc "Namespace of the workflow execution." + namespace: string, + /// @nexus.omit + control: placeholder, + /// @nexus.api-omit + /// @nexus.doc "Headers for the request." + /// @nexus.proto-field "header" + headers: option
, + /// @nexus.omit + links: placeholder, + /// @nexus.omit + time-skipping-config: placeholder, + } + + /// @nexus.doc "Result of signaling a workflow and starting it if needed." + /// @nexus.experimental + /// @nexus.proto "temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse" typescript-import="@temporalio/proto" + record signal-with-start-workflow-response { + /// @nexus.doc "Run ID of the started workflow." + run-id: option, + /// @nexus.doc "Whether the workflow was started." + started: option, + /// @nexus.omit + first-execution-run-id: placeholder, + /// @nexus.omit + signal-link: placeholder, + } + + /// @nexus.doc + /// "Signal a workflow, starting it first if needed." + /// go="Signal a workflow, starting it first if needed." + /// returns="A workflow handle to the started workflow." + /// @nexus.output-transform + /// java-type="io.temporal.workflow.ExternalWorkflowStub" + /// java="io.temporal.workflow.Workflow.newUntypedExternalWorkflowStub(io.temporal.api.common.v1.WorkflowExecution.newBuilder().setWorkflowId(request.getId()).setRunId(result.getRunId() == null ? \"\" : result.getRunId()).build())" + /// python-type="temporalio.workflow.ExternalWorkflowHandle[WorkflowResult]" + /// python="temporalio.workflow.get_external_workflow_handle(request.id, run_id=result.run_id)" + /// typescript-type="ExternalWorkflowHandle" + /// typescript-type-import="../../../../workflow" + /// typescript="workflow.getExternalWorkflowHandle(request.id, result.runId ?? undefined)" + /// typescript-import="@temporalio/workflow" + /// dotnet-type="Temporalio.Workflows.ExternalWorkflowHandle" + /// dotnet="Temporalio.Workflows.Workflow.GetExternalWorkflowHandle(request.Id, result.RunId)" + /// @nexus.operation name="SignalWithStartWorkflowExecution" + /// @nexus.serialization-context java="signalWithStartWorkflowSerializationContext" python="signal_with_start_workflow_serialization_context" typescript="signalWithStartWorkflowSerializationContext" dotnet="WorkflowServiceSerializationContexts.SignalWithStartWorkflow" go="SignalWithStartWorkflowSerializationContext" + /// @nexus.experimental + signal-with-start-workflow: func( + request: signal-with-start-workflow-request, + ) -> signal-with-start-workflow-response; +} diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java new file mode 100644 index 0000000000..04fedd2700 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java @@ -0,0 +1,293 @@ +package io.temporal.internal.nexus.system; + +import static org.junit.Assert.*; +import static org.mockito.AdditionalAnswers.delegatesTo; +import static org.mockito.Mockito.*; + +import com.google.protobuf.ByteString; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; +import io.temporal.common.converter.*; +import io.temporal.internal.payload.visitor.SystemNexusPayloads; +import io.temporal.payload.codec.PayloadCodec; +import io.temporal.payload.context.SerializationContext; +import io.temporal.payload.context.WorkflowSerializationContext; +import io.temporal.workflow.*; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.junit.Test; + +public class SystemNexusDataConverterTest { + private static final String SERVICE = "temporal.api.workflowservice.v1.WorkflowService"; + private static final String OPERATION = "SignalWithStartWorkflowExecution"; + + private static SignalWithStartWorkflowRequest request(String id) { + return SignalWithStartWorkflowRequest.newBuilder() + .setNamespace("destination") + .setId(id) + .setWorkflow("Target") + .setTaskQueue("queue") + .setSignal("notify") + .setArgs(Arrays.asList("workflow", 42)) + .setSignalArgs(Collections.singletonList("signal")) + .setMemo(Collections.singletonMap("memo", "value")) + .setHeaders( + Collections.singletonMap( + "trace", DefaultDataConverter.STANDARD_INSTANCE.toPayload("trace-value").get())) + .setUserMetadata(UserMetadata.newBuilder().setStaticSummary("summary").build()) + .build(); + } + + @Test + public void decodesUnmarkedServerResponse() { + Payload response = + SystemNexusPayloads.pack( + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse + .newBuilder() + .setRunId("run") + .setStarted(true) + .build()) + .toBuilder() + .removeMetadata("__temporal_system_payload") + .build(); + assertFalse(SystemNexusPayloads.isSystemPayload(response)); + SignalWithStartWorkflowResponse decoded = + new SystemNexusDataConverter(DefaultDataConverter.STANDARD_INSTANCE) + .fromPayload( + response, + SignalWithStartWorkflowResponse.class, + SignalWithStartWorkflowResponse.class); + assertEquals("run", decoded.getRunId()); + assertEquals(Boolean.TRUE, decoded.getStarted()); + } + + @Test + public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() throws Exception { + SignalWithStartWorkflowRequest request = request("target"); + WorkflowSerializationContext context = + (WorkflowSerializationContext) + SystemNexusOperations.serializationContext(SERVICE, OPERATION, request); + assertEquals("destination", context.getNamespace()); + assertEquals("target", context.getWorkflowId()); + DataConverter user = + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new ContextCodec(null))) + .withContext(context); + SystemNexusDataConverter converter = new SystemNexusDataConverter(user); + Payload encoded = converter.toPayload(request).get(); + assertTrue(SystemNexusPayloads.isSystemPayload(encoded)); + assertFalse(encoded.getMetadataMap().containsKey("test-context")); + SignalWithStartWorkflowExecutionRequest wire = + SignalWithStartWorkflowExecutionRequest.parseFrom(encoded.getData()); + assertEquals("", wire.getRequestId()); + assertEquals( + "target", wire.getInput().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); + assertEquals( + "target", + wire.getSignalInput().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); + assertEquals( + "target", + wire.getMemo().getFieldsOrThrow("memo").getMetadataOrThrow("test-context").toStringUtf8()); + SignalWithStartWorkflowRequest decoded = + converter.fromPayload( + encoded, SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class); + assertEquals(request.getArgs(), decoded.getArgs()); + assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); + assertEquals(request.getMemo(), decoded.getMemo()); + assertEquals(request.getHeaders(), decoded.getHeaders()); + assertEquals( + "target", + wire.getHeader() + .getFieldsOrThrow("trace") + .getMetadataOrThrow("test-context") + .toStringUtf8()); + assertEquals("summary", decoded.getUserMetadata().getStaticSummary()); + } + + @Test + public void customDataConverterReceivesUserValuesWithoutSystemEnvelopeHandling() + throws Exception { + SignalWithStartWorkflowRequest request = request("target"); + DataConverter user = + mock(DataConverter.class, delegatesTo(DefaultDataConverter.STANDARD_INSTANCE)); + SystemNexusDataConverter converter = new SystemNexusDataConverter(user); + Payload encoded = converter.toPayload(request).get(); + assertTrue(SystemNexusPayloads.isSystemPayload(encoded)); + SignalWithStartWorkflowExecutionRequest wire = + SignalWithStartWorkflowExecutionRequest.parseFrom(encoded.getData()); + assertEquals("target", wire.getWorkflowId()); + verify(user).toPayloads("workflow", 42); + verify(user).toPayloads("signal"); + verify(user).toPayload("value"); + verify(user, never()).toPayload(request); + verify(user, never()).toPayload(isA(com.google.protobuf.Message.class)); + SignalWithStartWorkflowRequest decoded = + converter.fromPayload( + encoded, SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class); + assertEquals(request.getArgs(), decoded.getArgs()); + assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); + assertEquals(request.getMemo(), decoded.getMemo()); + assertEquals(request.getHeaders(), decoded.getHeaders()); + } + + @Test + public void responseAndRawValuesRoundTripAndConverterScopesRestore() { + SystemNexusDataConverter converter = + new SystemNexusDataConverter(DefaultDataConverter.STANDARD_INSTANCE); + SignalWithStartWorkflowResponse response = + SignalWithStartWorkflowResponse.newBuilder().setRunId("run").setStarted(true).build(); + Payload encoded = converter.toPayload(response).get(); + assertEquals( + "run", + converter + .fromPayload( + encoded, + SignalWithStartWorkflowResponse.class, + SignalWithStartWorkflowResponse.class) + .getRunId()); + assertSame(encoded, converter.toPayload(new RawValue(encoded)).get()); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + } + + @Test + public void converterScopesRestoreAfterNestedFailure() { + DataConverter outer = DefaultDataConverter.STANDARD_INSTANCE; + DataConverter inner = new DefaultDataConverter(); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + SystemNexusDataConverter.withDataConverter( + outer, + () -> { + assertSame(outer, TemporalModelConverters.currentDataConverter()); + assertThrows( + IllegalArgumentException.class, + () -> + SystemNexusDataConverter.withDataConverter( + inner, + () -> { + assertSame(inner, TemporalModelConverters.currentDataConverter()); + throw new IllegalArgumentException("test"); + })); + assertSame(outer, TemporalModelConverters.currentDataConverter()); + return null; + }); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + } + + @Test + public void transferConversionRequiresActiveUserConverter() { + SignalWithStartWorkflowRequest.Converter converter = + new SignalWithStartWorkflowRequest.Converter(); + IllegalStateException encodeFailure = + assertThrows( + IllegalStateException.class, () -> converter.toTransferType(request("target"))); + assertEquals("System Nexus user converter context is not active", encodeFailure.getMessage()); + assertThrows( + IllegalStateException.class, + () -> + converter.fromTransferType( + SignalWithStartWorkflowExecutionRequest.getDefaultInstance(), + SignalWithStartWorkflowRequest.class)); + } + + @Test + public void operationsRetainIndependentDestinationConverters() { + SignalWithStartWorkflowRequest first = request("first"); + SignalWithStartWorkflowRequest second = request("second"); + DataConverter base = + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new ContextCodec(null))); + SystemNexusDataConverter firstConverter = + new SystemNexusDataConverter( + base.withContext( + SystemNexusOperations.serializationContext(SERVICE, OPERATION, first))); + SystemNexusDataConverter secondConverter = + new SystemNexusDataConverter( + base.withContext( + SystemNexusOperations.serializationContext(SERVICE, OPERATION, second))); + Payload firstPayload = firstConverter.toPayload(first).get(); + Payload secondPayload = secondConverter.toPayload(second).get(); + assertEquals( + "second", + secondConverter + .fromPayload( + secondPayload, + SignalWithStartWorkflowRequest.class, + SignalWithStartWorkflowRequest.class) + .getId()); + assertEquals( + "first", + firstConverter + .fromPayload( + firstPayload, + SignalWithStartWorkflowRequest.class, + SignalWithStartWorkflowRequest.class) + .getId()); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + } + + @Test + public void failuresAndEncodedAttributesUseTheDestinationConverter() { + DataConverter user = + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new ContextCodec(null)), + true) + .withContext(new WorkflowSerializationContext("destination", "target")); + SystemNexusDataConverter converter = new SystemNexusDataConverter(user); + io.temporal.api.failure.v1.Failure failure = + converter.exceptionToFailure( + io.temporal.failure.ApplicationFailure.newFailure("message", "type", "details")); + io.temporal.failure.ApplicationFailure decoded = + (io.temporal.failure.ApplicationFailure) converter.failureToException(failure); + assertEquals("message", decoded.getOriginalMessage()); + assertEquals("details", decoded.getDetails().get(0, String.class)); + } + + private static final class ContextCodec implements PayloadCodec { + private final String id; + + private ContextCodec(String id) { + this.id = id; + } + + @Nonnull + @Override + public PayloadCodec withContext(@Nonnull SerializationContext context) { + assertTrue(context instanceof WorkflowSerializationContext); + return new ContextCodec(((WorkflowSerializationContext) context).getWorkflowId()); + } + + @Nonnull + @Override + public List encode(@Nonnull List values) { + assertNotNull(id); + return values.stream() + .map( + value -> { + assertFalse(SystemNexusPayloads.isSystemPayload(value)); + assertFalse( + "Payload was encoded twice", + value.getMetadataMap().containsKey("test-context")); + return value.toBuilder() + .putMetadata("test-context", ByteString.copyFromUtf8(id)) + .build(); + }) + .collect(Collectors.toList()); + } + + @Nonnull + @Override + public List decode(@Nonnull List values) { + return values.stream() + .map( + value -> { + assertEquals(id, value.getMetadataOrThrow("test-context").toStringUtf8()); + return value.toBuilder().removeMetadata("test-context").build(); + }) + .collect(Collectors.toList()); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TemporalModelConvertersTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TemporalModelConvertersTest.java new file mode 100644 index 0000000000..c5ada24373 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TemporalModelConvertersTest.java @@ -0,0 +1,68 @@ +package io.temporal.internal.nexus.system; + +import static org.junit.Assert.*; + +import io.temporal.common.VersioningOverride; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.common.converter.DataConverter; +import io.temporal.common.converter.DefaultDataConverter; +import org.junit.Test; + +public class TemporalModelConvertersTest { + private static final DataConverter CONVERTER = DefaultDataConverter.STANDARD_INSTANCE; + + @Test + @SuppressWarnings("deprecation") + public void versioningOverridesRoundTripKnownShapes() { + WorkerDeploymentVersion version = new WorkerDeploymentVersion("deployment", "build"); + VersioningOverride.PinnedVersioningOverride pinned = + (VersioningOverride.PinnedVersioningOverride) + roundTrip(new VersioningOverride.PinnedVersioningOverride(version)); + assertEquals(version, pinned.getVersion()); + VersioningOverride.OneTimeVersioningOverride oneTime = + (VersioningOverride.OneTimeVersioningOverride) + roundTrip(new VersioningOverride.OneTimeVersioningOverride(version)); + assertEquals(version, oneTime.getTargetVersion()); + assertTrue( + roundTrip(new VersioningOverride.AutoUpgradeVersioningOverride()) + instanceof VersioningOverride.AutoUpgradeVersioningOverride); + VersioningOverride.PinnedVersioningOverride legacy = + (VersioningOverride.PinnedVersioningOverride) + TemporalModelConverters.versioningOverrideFromProto( + CONVERTER, + io.temporal.api.workflow.v1.VersioningOverride.newBuilder() + .setPinnedVersion("deployment.build") + .build()); + assertEquals(version, legacy.getVersion()); + } + + @Test + public void rejectsEmptyAndIncompleteVersioningOverrides() { + for (io.temporal.api.workflow.v1.VersioningOverride value : + new io.temporal.api.workflow.v1.VersioningOverride[] { + io.temporal.api.workflow.v1.VersioningOverride.getDefaultInstance(), + io.temporal.api.workflow.v1.VersioningOverride.newBuilder().setAutoUpgrade(false).build(), + io.temporal.api.workflow.v1.VersioningOverride.newBuilder() + .setPinned( + io.temporal.api.workflow.v1.VersioningOverride.PinnedOverride + .getDefaultInstance()) + .build(), + io.temporal.api.workflow.v1.VersioningOverride.newBuilder() + .setOneTime( + io.temporal.api.workflow.v1.VersioningOverride.OneTimeOverride + .getDefaultInstance()) + .build() + }) { + IllegalArgumentException error = + assertThrows( + IllegalArgumentException.class, + () -> TemporalModelConverters.versioningOverrideFromProto(CONVERTER, value)); + assertEquals("Unknown versioning override proto shape", error.getMessage()); + } + } + + private static VersioningOverride roundTrip(VersioningOverride value) { + return TemporalModelConverters.versioningOverrideFromProto( + CONVERTER, TemporalModelConverters.versioningOverrideToProto(CONVERTER, value)); + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java new file mode 100644 index 0000000000..14a84aca76 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java @@ -0,0 +1,257 @@ +package io.temporal.internal.nexus.system; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.common.CronSchedule; +import io.temporal.common.MethodRetry; +import io.temporal.common.RetryOptions; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; +import io.temporal.common.metadata.WorkflowMethodType; +import io.temporal.internal.sync.ExternalWorkflowInvocationHandler; +import io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult; +import io.temporal.internal.sync.StubMarker; +import io.temporal.workflow.*; +import java.lang.reflect.Proxy; +import java.util.List; +import java.util.concurrent.*; +import org.junit.Test; + +public class TypedWorkflowMethodCaptureTest { + public interface Base { + @SignalMethod(name = "custom-signal") + void signal(String value, int number); + } + + @WorkflowInterface + public interface Target extends Base { + @WorkflowMethod(name = "custom-workflow") + @MethodRetry( + initialIntervalSeconds = 7, + maximumAttempts = 3, + backoffCoefficient = 3, + maximumIntervalSeconds = 100, + doNotRetry = {"NoRetry"}) + @CronSchedule("0 * * * *") + int start(String value); + + @QueryMethod + String query(); + + @UpdateMethod + String update(); + } + + @WorkflowInterface + public interface GenericTarget { + @WorkflowMethod + List start(); + } + + private final WorkflowOutboundCallsInterceptor outbound = + mock(WorkflowOutboundCallsInterceptor.class); + private final RuntimeException normalSignal = new IllegalStateException("normal signal path"); + + private T stub(Class type, String id) { + return type.cast( + Proxy.newProxyInstance( + type.getClassLoader(), + new Class[] {type, StubMarker.class}, + new ExternalWorkflowInvocationHandler( + type, + WorkflowExecution.newBuilder().setWorkflowId(id).build(), + outbound, + ignored -> { + throw normalSignal; + }))); + } + + @Test + public void probesNamesArgumentsAnnotationsAndReturnTypesWithoutCommands() { + Target target = stub(Target.class, "target"); + Functions.Func1 method = target::start; + ProbeResult call = + ExternalWorkflowInvocationHandler.probe( + method, + () -> assertEquals(0, (int) method.apply("input")), + WorkflowMethodType.WORKFLOW); + assertEquals("custom-workflow", call.getName()); + assertArrayEquals(new Object[] {"input"}, call.getArguments()); + assertEquals(int.class, call.getResultClass()); + assertEquals(int.class, call.getResultType()); + assertEquals("target", call.getStub().getExecution().getWorkflowId()); + assertEquals(3, call.getMethod().getAnnotation(MethodRetry.class).maximumAttempts()); + assertEquals("0 * * * *", call.getMethod().getAnnotation(CronSchedule.class).value()); + assertSame(ExternalWorkflowStub.fromTyped(target), call.getStub()); + call.getArguments()[0] = "changed"; + assertEquals("input", call.getArguments()[0]); + + Functions.Proc2 signal = target::signal; + ProbeResult signalCall = + ExternalWorkflowInvocationHandler.probe( + signal, () -> signal.apply("value", 42), WorkflowMethodType.SIGNAL); + assertEquals("custom-signal", signalCall.getName()); + assertArrayEquals(new Object[] {"value", 42}, signalCall.getArguments()); + GenericTarget generic = stub(GenericTarget.class, "generic"); + Functions.Func> start = generic::start; + ProbeResult genericCall = + ExternalWorkflowInvocationHandler.probe( + start, () -> start.apply(), WorkflowMethodType.WORKFLOW); + assertEquals("java.util.List", genericCall.getResultType().getTypeName()); + verifyNoInteractions(outbound); + assertThrows(IllegalStateException.class, () -> target.start("outside probe")); + assertSame( + normalSignal, assertThrows(RuntimeException.class, () -> target.signal("outside", 1))); + } + + @Test + public void mergesOriginalAnnotationsWithExplicitValuesWithoutPrematureDefaults() { + Target target = stub(Target.class, "target"); + Functions.Func1 method = target::start; + ProbeResult call = + ExternalWorkflowInvocationHandler.probe( + method, () -> method.apply("input"), WorkflowMethodType.WORKFLOW); + RetryOptions defaults = TemporalModelConverters.mergeMethodRetry(call, null); + assertEquals(java.time.Duration.ofSeconds(7), defaults.getInitialInterval()); + assertEquals(3, defaults.getMaximumAttempts()); + assertEquals(3.0, defaults.getBackoffCoefficient(), 0); + RetryOptions explicit = RetryOptions.newBuilder().setMaximumAttempts(9).build(); + RetryOptions merged = TemporalModelConverters.mergeMethodRetry(call, explicit); + assertEquals(9, merged.getMaximumAttempts()); + assertEquals(java.time.Duration.ofSeconds(7), merged.getInitialInterval()); + assertEquals(java.time.Duration.ofSeconds(100), merged.getMaximumInterval()); + assertEquals(3.0, merged.getBackoffCoefficient(), 0); + assertArrayEquals(new String[] {"NoRetry"}, merged.getDoNotRetry()); + assertNull(explicit.getInitialInterval()); + assertEquals("0 * * * *", TemporalModelConverters.mergeCronSchedule(call, null)); + assertEquals("1 * * * *", TemporalModelConverters.mergeCronSchedule(call, "1 * * * *")); + assertEquals("", TemporalModelConverters.mergeCronSchedule(call, "")); + + GenericTarget plain = stub(GenericTarget.class, "plain"); + Functions.Func> plainMethod = plain::start; + ProbeResult noAnnotations = + ExternalWorkflowInvocationHandler.probe( + plainMethod, () -> plainMethod.apply(), WorkflowMethodType.WORKFLOW); + assertNull(TemporalModelConverters.mergeMethodRetry(noAnnotations, null)); + assertSame(explicit, TemporalModelConverters.mergeMethodRetry(noAnnotations, explicit)); + assertNull(TemporalModelConverters.mergeCronSchedule(noAnnotations, null)); + assertEquals("", TemporalModelConverters.mergeCronSchedule(noAnnotations, "")); + verifyNoInteractions(outbound); + } + + @Test + public void rejectsMissingRepeatedWrongKindAndNonBoundInvocations() { + Target target = stub(Target.class, "target"); + Functions.Func1 start = target::start; + assertThrows( + IllegalArgumentException.class, + () -> + ExternalWorkflowInvocationHandler.probe(start, () -> {}, WorkflowMethodType.WORKFLOW)); + assertThrows( + IllegalArgumentException.class, + () -> + ExternalWorkflowInvocationHandler.probe( + start, + () -> { + start.apply("first"); + start.apply("second"); + }, + WorkflowMethodType.WORKFLOW)); + assertThrows( + IllegalArgumentException.class, + () -> + ExternalWorkflowInvocationHandler.probe( + start, () -> start.apply("input"), WorkflowMethodType.SIGNAL)); + Functions.Proc2 signal = target::signal; + assertThrows( + IllegalArgumentException.class, + () -> + ExternalWorkflowInvocationHandler.probe( + signal, () -> signal.apply("value", 1), WorkflowMethodType.WORKFLOW)); + Functions.Func query = target::query; + Functions.Func update = target::update; + assertThrows( + IllegalArgumentException.class, + () -> + ExternalWorkflowInvocationHandler.probe( + query, () -> query.apply(), WorkflowMethodType.SIGNAL)); + assertThrows( + IllegalArgumentException.class, + () -> + ExternalWorkflowInvocationHandler.probe( + update, () -> update.apply(), WorkflowMethodType.SIGNAL)); + Functions.Proc lambda = () -> target.start("input"); + assertThrows( + IllegalArgumentException.class, + () -> ExternalWorkflowInvocationHandler.probe(lambda, lambda, WorkflowMethodType.WORKFLOW)); + verifyNoInteractions(outbound); + } + + @Test + public void restoresProbeStateAfterFailureAndRejectsNesting() { + Target target = stub(Target.class, "target"); + Functions.Func1 method = target::start; + RuntimeException failure = new RuntimeException("failed"); + assertSame( + failure, + assertThrows( + RuntimeException.class, + () -> + ExternalWorkflowInvocationHandler.probe( + method, + () -> { + throw failure; + }, + WorkflowMethodType.WORKFLOW))); + ProbeResult result = + ExternalWorkflowInvocationHandler.probe( + method, + () -> { + assertThrows( + IllegalStateException.class, + () -> + ExternalWorkflowInvocationHandler.probe( + method, () -> method.apply("nested"), WorkflowMethodType.WORKFLOW)); + method.apply("outer"); + }, + WorkflowMethodType.WORKFLOW); + assertArrayEquals(new Object[] {"outer"}, result.getArguments()); + assertThrows(IllegalStateException.class, () -> target.start("outside probe")); + verifyNoInteractions(outbound); + } + + @Test + public void isolatesProbeResultsAcrossThreads() throws Exception { + Target first = stub(Target.class, "first"); + Target second = stub(Target.class, "second"); + CyclicBarrier barrier = new CyclicBarrier(2); + ExecutorService executor = Executors.newFixedThreadPool(2); + try { + Future a = executor.submit(() -> parallelProbe(first::start, "a", barrier)); + Future b = executor.submit(() -> parallelProbe(second::start, "b", barrier)); + assertEquals("first:a", a.get(10, TimeUnit.SECONDS)); + assertEquals("second:b", b.get(10, TimeUnit.SECONDS)); + } finally { + executor.shutdownNow(); + } + verifyNoInteractions(outbound); + } + + private String parallelProbe( + Functions.Func1 method, String value, CyclicBarrier barrier) { + ProbeResult result = + ExternalWorkflowInvocationHandler.probe( + method, + () -> { + try { + barrier.await(5, TimeUnit.SECONDS); + } catch (Exception e) { + throw new RuntimeException(e); + } + method.apply(value); + }, + WorkflowMethodType.WORKFLOW); + return result.getStub().getExecution().getWorkflowId() + ":" + result.getArguments()[0]; + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageRunnerTest.java b/temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageRunnerTest.java index 323ef817fe..13ecf06ce3 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageRunnerTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageRunnerTest.java @@ -36,6 +36,34 @@ /** Tests external storage message conversion. */ public class ExternalStorageRunnerTest { + @Test + public void systemEnvelopeOffloadsOnlyNestedPayloads() throws Exception { + TestStorageDriver driver = TestStorageDriver.named("system"); + ExternalStorageRunner transformer = transformer(driver, 0); + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest request = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder() + .setInput(Payloads.newBuilder().addPayloads(payload("workflow"))) + .setSignalInput(Payloads.newBuilder().addPayloads(payload("signal"))) + .setSearchAttributes( + SearchAttributes.newBuilder().putIndexedFields("key", payload("search"))) + .build(); + Payload envelope = io.temporal.internal.payload.visitor.SystemNexusPayloads.pack(request); + Payloads original = Payloads.newBuilder().addPayloads(envelope).build(); + Payloads.Builder builder = original.toBuilder(); + transformer.store(builder, null, null, CancellationToken.none()); + Payload stored = builder.getPayloads(0); + assertTrue(io.temporal.internal.payload.visitor.SystemNexusPayloads.isSystemPayload(stored)); + assertNull(ExternalStorageReferences.tryParseReference(stored)); + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest nested = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.parseFrom( + stored.getData()); + assertNotNull(ExternalStorageReferences.tryParseReference(nested.getInput().getPayloads(0))); + assertNotNull( + ExternalStorageReferences.tryParseReference(nested.getSignalInput().getPayloads(0))); + assertEquals(request.getSearchAttributes(), nested.getSearchAttributes()); + assertEquals(original, transformer.retrieve(builder.build(), CancellationToken.none())); + } + @Test public void storeAndRetrieveRoundTripsOverAMessage() throws Exception { TestStorageDriver driver = TestStorageDriver.named("d1"); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java new file mode 100644 index 0000000000..f1c3c96b49 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -0,0 +1,273 @@ +package io.temporal.workflow.nexus; + +import static org.junit.Assert.*; + +import io.temporal.common.interceptors.*; +import io.temporal.testing.internal.SDKTestWorkflowRule; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.*; +import io.temporal.workflow.SignalWithStartWorkflowRequest; +import io.temporal.workflow.SignalWithStartWorkflowResponse; +import org.junit.Rule; +import org.junit.Test; + +public class SignalWithStartWorkflowTest { + @Rule + public SDKTestWorkflowRule rule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(CallerImpl.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors( + new WorkerInterceptorBase() { + @Override + public WorkflowInboundCallsInterceptor interceptWorkflow( + WorkflowInboundCallsInterceptor next) { + return new WorkflowInboundCallsInterceptorBase(next) { + @Override + public void init(WorkflowOutboundCallsInterceptor outbound) { + super.init( + new WorkflowOutboundCallsInterceptorBase(outbound) { + @Override + public ExecuteNexusOperationOutput< + SignalWithStartWorkflowResponse> + executeSignalWithStartWorkflow( + ExecuteNexusOperationInput< + SignalWithStartWorkflowResponse> + input) { + SignalWithStartWorkflowRequest request = + (SignalWithStartWorkflowRequest) input.getArg(); + assertEquals("Target", request.getWorkflow()); + assertEquals( + Workflow.getInfo().getNamespace(), + request.getNamespace()); + assertEquals("notify", request.getSignal()); + assertEquals("queue", request.getTaskQueue()); + if (request.getId().startsWith("typed")) { + assertEquals( + java.time.Duration.ofSeconds(7), + request.getRetryPolicy().getInitialInterval()); + assertEquals( + request.getId().equals("typed-async") ? 9 : 3, + request.getRetryPolicy().getMaximumAttempts()); + assertEquals( + request.getId().equals("typed-async") + ? "" + : "0 * * * *", + request.getCronSchedule()); + } else { + assertNull(request.getRetryPolicy()); + assertNull(request.getCronSchedule()); + } + assertEquals( + io.temporal.api.enums.v1.WorkflowIdReusePolicy + .WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE, + request.getIdReusePolicy()); + if (request.getId().contains("defaults")) { + assertTrue(request.getArgs().isEmpty()); + assertTrue(request.getSignalArgs().isEmpty()); + } else { + assertEquals("input", request.getArgs().get(0)); + if (request.getId().equals("arity6")) { + assertEquals( + java.util.Arrays.asList( + "input", + 2, + 3L, + true, + java.util.Collections.singletonList("nested"), + java.util.Collections.singletonMap("key", 4)), + request.getArgs()); + } + assertEquals("signal", request.getSignalArgs().get(0)); + assertEquals( + "summary", + request.getUserMetadata().getStaticSummary()); + assertEquals( + java.time.Duration.ofMinutes(3), + request.getRunTimeout()); + } + return new ExecuteNexusOperationOutput<>( + Workflow.newPromise( + SignalWithStartWorkflowResponse.newBuilder() + .setRunId("run") + .build()), + Workflow.newPromise(() -> java.util.Optional.empty())); + } + }); + } + }; + } + }) + .build()) + .build(); + + @Test + public void generatedWorkflowMethodsReturnExternalStubs() { + assertEquals( + "sync:run,async:run,defaults:run,typed:run,typed-async:run,typed-defaults:run,typed-null-defaults:run,arity6:run", + rule.newWorkflowStubTimeoutOptions(Caller.class).run()); + } + + @WorkflowInterface + public interface TypedTarget { + @WorkflowMethod(name = "Target") + @io.temporal.common.MethodRetry(initialIntervalSeconds = 7, maximumAttempts = 3) + @io.temporal.common.CronSchedule("0 * * * *") + int start(String input); + + @SignalMethod(name = "notify") + @io.temporal.common.MethodRetry(maximumAttempts = 99) + @io.temporal.common.CronSchedule("signal-annotation-must-not-be-used") + void signalValue(String value); + } + + @WorkflowInterface + public interface EmptyTarget { + @WorkflowMethod(name = "Target") + @io.temporal.common.MethodRetry(initialIntervalSeconds = 7, maximumAttempts = 3) + @io.temporal.common.CronSchedule("0 * * * *") + void start(); + + @SignalMethod(name = "notify") + void signalValue(); + } + + @WorkflowInterface + public interface SixArgumentTarget { + @WorkflowMethod(name = "Target") + java.util.List start( + String first, + int second, + long third, + boolean fourth, + java.util.List fifth, + java.util.Map sixth); + + @SignalMethod(name = "notify") + void signalValue(String value); + } + + @WorkflowInterface + public interface Caller { + @WorkflowMethod + String run(); + } + + public static class CallerImpl implements Caller { + @Override + public String run() { + SignalWithStartWorkflowOptions options = + SignalWithStartWorkflowOptions.newBuilder() + .setStaticSummary("summary") + .setRunTimeout(java.time.Duration.ofMinutes(3)) + .build(); + ExternalWorkflowStub sync = + Workflow.signalWithStartWorkflow( + "Target", + new Object[] {"input"}, + "sync", + "queue", + "notify", + new Object[] {"signal"}, + options); + ExternalWorkflowStub async = + Async.function( + () -> + Workflow.signalWithStartWorkflow( + "Target", + new Object[] {"input"}, + "async", + "queue", + "notify", + new Object[] {"signal"}, + options.toBuilder().build())) + .get(); + ExternalWorkflowStub defaults = + Workflow.signalWithStartWorkflow( + "Target", new Object[0], "defaults", "queue", "notify", new Object[0]); + SignalWithStartWorkflowOptions typedOptions = options; + TypedTarget target = Workflow.newExternalWorkflowStub(TypedTarget.class, "typed"); + ExternalWorkflowStub typed = + Workflow.signalWithStartWorkflow( + target::start, + "input", + "typed", + "queue", + target::signalValue, + "signal", + typedOptions); + ExternalWorkflowStub typedAsync = + Async.function( + () -> + Workflow.signalWithStartWorkflow( + target::start, + "input", + "typed-async", + "queue", + target::signalValue, + "signal", + typedOptions.toBuilder() + .setRetryPolicy( + io.temporal.common.RetryOptions.newBuilder() + .setMaximumAttempts(9) + .build()) + .setCronSchedule("") + .build())) + .get(); + EmptyTarget empty = Workflow.newExternalWorkflowStub(EmptyTarget.class, "typed-defaults"); + ExternalWorkflowStub typedDefaults = + Workflow.signalWithStartWorkflow( + empty::start, "typed-defaults", "queue", empty::signalValue); + ExternalWorkflowStub typedNull = + Workflow.signalWithStartWorkflow( + empty::start, "typed-null-defaults", "queue", empty::signalValue, null); + SixArgumentTarget six = Workflow.newExternalWorkflowStub(SixArgumentTarget.class, "arity6"); + ExternalWorkflowStub arity6 = + Workflow.signalWithStartWorkflow( + six::start, + "input", + 2, + 3L, + true, + java.util.Collections.singletonList("nested"), + java.util.Collections.singletonMap("key", 4), + "arity6", + "queue", + six::signalValue, + "signal", + typedOptions); + return sync.getExecution().getWorkflowId() + + ":" + + sync.getExecution().getRunId() + + "," + + async.getExecution().getWorkflowId() + + ":" + + async.getExecution().getRunId() + + "," + + defaults.getExecution().getWorkflowId() + + ":" + + defaults.getExecution().getRunId() + + "," + + typed.getExecution().getWorkflowId() + + ":" + + typed.getExecution().getRunId() + + "," + + typedAsync.getExecution().getWorkflowId() + + ":" + + typedAsync.getExecution().getRunId() + + "," + + typedDefaults.getExecution().getWorkflowId() + + ":" + + typedDefaults.getExecution().getRunId() + + "," + + typedNull.getExecution().getWorkflowId() + + ":" + + typedNull.getExecution().getRunId() + + "," + + arity6.getExecution().getWorkflowId() + + ":" + + arity6.getExecution().getRunId(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java new file mode 100644 index 0000000000..ea0266a127 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -0,0 +1,281 @@ +package io.temporal.workflow.nexus; + +import static org.junit.Assert.*; + +import com.google.protobuf.ByteString; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.common.converter.CodecDataConverter; +import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.internal.payload.visitor.SystemNexusPayloads; +import io.temporal.payload.codec.PayloadCodec; +import io.temporal.payload.context.SerializationContext; +import io.temporal.payload.context.WorkflowSerializationContext; +import io.temporal.testing.CloudTestExclusion.RequiresCloudProvisioning; +import io.temporal.testing.CloudTestExclusionNote; +import io.temporal.testing.WorkflowReplayer; +import io.temporal.testing.internal.SDKTestWorkflowRule; +import io.temporal.workflow.*; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@CloudTestExclusionNote("Requires a server supporting the Temporal system Nexus workflow service.") +@Category(RequiresCloudProvisioning.class) +public class SystemSignalWithStartIntegrationTest { + @Rule + public SDKTestWorkflowRule rule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(CallerImpl.class, ConcurrentCallerImpl.class, TargetImpl.class) + .setWorkflowClientOptions( + WorkflowClientOptions.newBuilder() + .setDataConverter( + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new DestinationCodec(null)))) + .build()) + .build(); + + @Before + public void requireSystemService() { + Assume.assumeTrue( + "System Nexus requires a supporting external server", + SDKTestWorkflowRule.useExternalService); + } + + @Test + public void startsThenSignalsTheExistingExecutionAndReplays() throws Exception { + Caller caller = rule.newWorkflowStubTimeoutOptions(Caller.class); + String target = caller.run(); + assertEquals( + "start:first:second", + rule.getWorkflowClient().newUntypedWorkflowStub(target).getResult(String.class)); + String callerId = + io.temporal.client.WorkflowStub.fromTyped(caller).getExecution().getWorkflowId(); + WorkflowReplayer.replayWorkflowExecution(rule.getExecutionHistory(callerId), rule.getWorker()); + } + + @Test + public void concurrentCallsUseDestinationCodecContextAndPreserveOuterEnvelopes() + throws Exception { + ConcurrentCaller caller = rule.newWorkflowStubTimeoutOptions(ConcurrentCaller.class); + List targets = caller.run(); + for (String target : targets) { + assertEquals( + "start:first:second", + rule.getWorkflowClient().newUntypedWorkflowStub(target).getResult(String.class)); + } + String callerId = WorkflowStub.fromTyped(caller).getExecution().getWorkflowId(); + int scheduled = 0; + for (HistoryEvent event : rule.getExecutionHistory(callerId).getEvents()) { + if (!event.hasNexusOperationScheduledEventAttributes()) continue; + scheduled++; + Payload envelope = event.getNexusOperationScheduledEventAttributes().getInput(); + assertTrue(SystemNexusPayloads.isSystemPayload(envelope)); + assertFalse(envelope.containsMetadata(DestinationCodec.KEY)); + SignalWithStartWorkflowExecutionRequest request = + SignalWithStartWorkflowExecutionRequest.parseFrom(envelope.getData()); + assertTrue(targets.contains(request.getWorkflowId())); + String expected = request.getNamespace() + "/" + request.getWorkflowId(); + List embedded = new ArrayList<>(); + embedded.addAll(request.getInput().getPayloadsList()); + embedded.addAll(request.getSignalInput().getPayloadsList()); + embedded.addAll(request.getMemo().getFieldsMap().values()); + embedded.add(request.getUserMetadata().getSummary()); + embedded.add(request.getUserMetadata().getDetails()); + assertEquals(5, embedded.size()); + for (Payload payload : embedded) { + assertEquals(expected, payload.getMetadataOrThrow(DestinationCodec.KEY).toStringUtf8()); + } + } + assertEquals(4, scheduled); + WorkflowReplayer.replayWorkflowExecution(rule.getExecutionHistory(callerId), rule.getWorker()); + } + + @WorkflowInterface + public interface ConcurrentCaller { + @WorkflowMethod + List run(); + } + + public static class ConcurrentCallerImpl implements ConcurrentCaller { + @Override + public List run() { + List targets = + Arrays.asList( + Workflow.getInfo().getWorkflowId() + "-first", + Workflow.getInfo().getWorkflowId() + "-second"); + List> calls = new ArrayList<>(); + for (String id : targets) { + calls.add( + Async.procedure( + () -> { + SignalWithStartWorkflowOptions options = + SignalWithStartWorkflowOptions.newBuilder() + .setCronSchedule("") + .setIdConflictPolicy( + WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) + .setMemo(Collections.singletonMap("memo", "memo-value")) + .setStaticSummary("summary") + .setStaticDetails("details") + .build(); + Target target = Workflow.newExternalWorkflowStub(Target.class, id); + Workflow.signalWithStartWorkflow( + target::run, + "start", + id, + Workflow.getInfo().getTaskQueue(), + target::notifySignal, + "first", + options); + Workflow.signalWithStartWorkflow( + "SystemSignalTarget", + new Object[] {"ignored"}, + id, + Workflow.getInfo().getTaskQueue(), + "notifySignal", + new Object[] {"second"}, + options); + })); + } + Promise.allOf(calls).get(); + return targets; + } + } + + private static final class DestinationCodec implements PayloadCodec { + static final String KEY = "test-destination"; + private final String destination; + + DestinationCodec(String destination) { + this.destination = destination; + } + + @Nonnull + @Override + public PayloadCodec withContext(@Nonnull SerializationContext context) { + if (!(context instanceof WorkflowSerializationContext)) return this; + WorkflowSerializationContext workflow = (WorkflowSerializationContext) context; + return new DestinationCodec(workflow.getNamespace() + "/" + workflow.getWorkflowId()); + } + + @Nonnull + @Override + public List encode(@Nonnull List payloads) { + return payloads.stream() + .map( + payload -> { + rejectEnvelope(payload); + assertFalse("Payload encoded twice", payload.containsMetadata(KEY)); + return destination == null + ? payload + : payload.toBuilder() + .putMetadata(KEY, ByteString.copyFromUtf8(destination)) + .build(); + }) + .collect(Collectors.toList()); + } + + @Nonnull + @Override + public List decode(@Nonnull List payloads) { + return payloads.stream() + .map( + payload -> { + rejectEnvelope(payload); + if (!payload.containsMetadata(KEY)) return payload; + assertEquals(destination, payload.getMetadataOrThrow(KEY).toStringUtf8()); + return payload.toBuilder().removeMetadata(KEY).build(); + }) + .collect(Collectors.toList()); + } + + private static void rejectEnvelope(Payload payload) { + assertFalse( + "System envelope passed to the user codec", SystemNexusPayloads.isSystemPayload(payload)); + ByteString type = payload.getMetadataMap().get("messageType"); + assertFalse( + "Unmarked system response passed to the user codec", + type != null + && type.toStringUtf8() + .startsWith("temporal.api.workflowservice.v1.SignalWithStartWorkflowExecution")); + } + } + + @WorkflowInterface + public interface Target { + @WorkflowMethod(name = "SystemSignalTarget") + @io.temporal.common.MethodRetry(initialIntervalSeconds = 1, maximumAttempts = 3) + @io.temporal.common.CronSchedule("0 * * * *") + String run(String initial); + + @SignalMethod + void notifySignal(String value); + } + + public static class TargetImpl implements Target { + private final java.util.List signals = new java.util.ArrayList<>(); + + @Override + public String run(String initial) { + Workflow.await(() -> signals.size() == 2); + return initial + ":" + String.join(":", signals); + } + + @Override + public void notifySignal(String value) { + signals.add(value); + } + } + + @WorkflowInterface + public interface Caller { + @WorkflowMethod + String run(); + } + + public static class CallerImpl implements Caller { + @Override + public String run() { + String id = Workflow.getInfo().getWorkflowId() + "-target"; + SignalWithStartWorkflowOptions options = + SignalWithStartWorkflowOptions.newBuilder() + .setCronSchedule("") + .setIdConflictPolicy( + WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) + .build(); + Target target = Workflow.newExternalWorkflowStub(Target.class, id); + ExternalWorkflowStub external = + Workflow.signalWithStartWorkflow( + target::run, + "start", + id, + Workflow.getInfo().getTaskQueue(), + target::notifySignal, + "first", + options); + assertEquals(id, external.getExecution().getWorkflowId()); + Async.function( + () -> + Workflow.signalWithStartWorkflow( + "SystemSignalTarget", + new Object[] {"ignored"}, + id, + Workflow.getInfo().getTaskQueue(), + "notifySignal", + new Object[] {"second"}, + options)) + .get(); + return id; + } + } +} diff --git a/temporal-serviceclient/build.gradle b/temporal-serviceclient/build.gradle index ec63fa64bf..e653778ef7 100644 --- a/temporal-serviceclient/build.gradle +++ b/temporal-serviceclient/build.gradle @@ -149,15 +149,19 @@ sourceSets { dependencies { payloadGeneratorsImplementation "com.google.protobuf:protobuf-java:$protoVersion" + testImplementation sourceSets.payloadGenerators.output } def generatedPayloadVisitorDir = layout.buildDirectory.dir('generated/payloadvisitor/java') def generatePayloadVisitor = tasks.register('generatePayloadVisitor', JavaExec) { dependsOn 'compilePayloadGeneratorsJava', 'generateProto' + mustRunAfter ':temporal-sdk:generateNexusSystemApi' classpath = sourceSets.payloadGenerators.runtimeClasspath mainClass = 'io.temporal.internal.payload.visitor.gen.PayloadVisitorGenerator' - args apiDescriptorSet.get().asFile.absolutePath, generatedPayloadVisitorDir.get().asFile.absolutePath + def systemRoots = project(':temporal-sdk').file('src/main/generated/io/temporal/workflow/system-nexus-roots.txt') + args apiDescriptorSet.get().asFile.absolutePath, generatedPayloadVisitorDir.get().asFile.absolutePath, systemRoots.absolutePath + inputs.file(systemRoots) inputs.file(apiDescriptorSet) inputs.files(sourceSets.payloadGenerators.runtimeClasspath) outputs.dir(generatedPayloadVisitorDir) diff --git a/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java new file mode 100644 index 0000000000..03eed8a3c6 --- /dev/null +++ b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java @@ -0,0 +1,49 @@ +package io.temporal.internal.payload.visitor; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import io.temporal.api.common.v1.Payload; + +/** Fixed binary protobuf envelopes used by Temporal system Nexus operations. */ +public final class SystemNexusPayloads { + private static final String MARKER = "__temporal_system_payload"; + private static final ByteString TRUE = ByteString.copyFromUtf8("true"); + private static final ByteString ENCODING = ByteString.copyFromUtf8("binary/protobuf"); + + private SystemNexusPayloads() {} + + public static boolean isSystemPayload(Payload payload) { + return TRUE.equals(payload.getMetadataMap().get(MARKER)); + } + + public static Payload pack(Message message) { + return Payload.newBuilder() + .putMetadata(MARKER, TRUE) + .putMetadata("encoding", ENCODING) + .putMetadata( + "messageType", ByteString.copyFromUtf8(message.getDescriptorForType().getFullName())) + .setData(message.toByteString()) + .build(); + } + + public static Message.Builder unpack(Payload payload) { + // The marker controls generic visitation. Server responses use the same binary envelope + // without the marker and are decoded in the system operation's known converter scope. + if (!ENCODING.equals(payload.getMetadataMap().get("encoding"))) { + throw new VisitorException("Invalid Temporal system payload encoding"); + } + ByteString type = payload.getMetadataMap().get("messageType"); + String name = type == null ? "" : type.toStringUtf8(); + MessageRegistryEntry entry = GeneratedPayloadVisitor.SYSTEM_ROOTS.get(name); + if (entry == null) { + throw new VisitorException("Unknown Temporal system payload: " + name); + } + Message.Builder builder = entry.newBuilder.get(); + try { + return builder.mergeFrom(payload.getData()); + } catch (InvalidProtocolBufferException e) { + throw new VisitorException("Failed to unpack Temporal system payload: " + name, e); + } + } +} diff --git a/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/Traversal.java b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/Traversal.java index ffbdd712ce..570d8bd7c0 100644 --- a/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/Traversal.java +++ b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/Traversal.java @@ -82,7 +82,27 @@ void exit(Object previous) { /** Record a visit of a payload sequence (a {@code Payloads} or {@code repeated Payload}). */ void payloads(List batch, Consumer> writeBack) { + if (batch.stream().anyMatch(SystemNexusPayloads::isSystemPayload)) { + List result = new ArrayList<>(); + // Keep ordinary sequences batched: codecs may change their cardinality. + int start = 0; + for (int i = 0; i < batch.size(); i++) { + if (SystemNexusPayloads.isSystemPayload(batch.get(i))) { + if (start < i) { + payloads(batch.subList(start, i), result::addAll); + } + systemPayload(batch.get(i), result::add); + start = i + 1; + } + } + if (start < batch.size()) { + payloads(batch.subList(start, batch.size()), result::addAll); + } + deferWriteBack(() -> writeBack.accept(result)); + return; + } if (payloadVisitor == null) { + deferWriteBack(() -> writeBack.accept(batch)); return; } LeafJob job = new LeafJob(batch, currentContext, false); @@ -92,6 +112,10 @@ void payloads(List batch, Consumer> writeBack) { /** The visitor must return exactly one payload (checked in {@link #record}). */ void singlePayload(Payload value, Consumer writeBack) { + if (SystemNexusPayloads.isSystemPayload(value)) { + systemPayload(value, writeBack); + return; + } if (payloadVisitor == null) { return; } @@ -100,6 +124,13 @@ void singlePayload(Payload value, Consumer writeBack) { writeBacks.add(() -> writeBack.accept(job.result.get(0))); } + private void systemPayload(Payload value, Consumer writeBack) { + Message.Builder inner = SystemNexusPayloads.unpack(value); + dispatch(inner); + deferWriteBack( + () -> writeBack.accept(value.toBuilder().setData(inner.build().toByteString()).build())); + } + /** Applied after all visits, single-threaded, in walk order. */ void deferWriteBack(Runnable writeBack) { writeBacks.add(writeBack); diff --git a/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/gen/ProtoClosure.java b/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/gen/ProtoClosure.java index 9d71f8e16c..c7597fd6eb 100644 --- a/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/gen/ProtoClosure.java +++ b/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/gen/ProtoClosure.java @@ -48,7 +48,27 @@ public boolean reaches(Descriptor d) { /** Builds the closure and payload-reachability set from the given seed file descriptors. */ public static ProtoClosure of(List seeds) { + return of(seeds, java.util.Collections.emptyList()); + } + + /** + * Adds message roots and their reachable fields without requiring their files to be service + * seeds. + */ + public static ProtoClosure of(List seeds, List roots) { List all = collectMessages(fileClosure(seeds)); + Set seen = new HashSet<>(); + for (Descriptor descriptor : all) seen.add(descriptor.getFullName()); + Deque queue = new ArrayDeque<>(roots); + while (!queue.isEmpty()) { + Descriptor descriptor = queue.remove(); + if (!seen.add(descriptor.getFullName())) continue; + if (!descriptor.getOptions().getMapEntry()) all.add(descriptor); + for (FieldDescriptor field : descriptor.getFields()) { + if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) + queue.add(field.getMessageType()); + } + } return new ProtoClosure(all, computeReachability(all)); } diff --git a/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/visitor/gen/PayloadVisitorGenerator.java b/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/visitor/gen/PayloadVisitorGenerator.java index bbe19c1594..87e807ed0c 100644 --- a/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/visitor/gen/PayloadVisitorGenerator.java +++ b/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/visitor/gen/PayloadVisitorGenerator.java @@ -87,29 +87,55 @@ public static void main(String[] args) throws Exception { throw new IllegalArgumentException( "usage: PayloadVisitorGenerator "); } - new PayloadVisitorGenerator().run(Paths.get(args[0]), Paths.get(args[1])); + new PayloadVisitorGenerator() + .run(Paths.get(args[0]), Paths.get(args[1]), args.length > 2 ? Paths.get(args[2]) : null); } private ProtoClosure closure; + private final java.util.Set systemRoots = new java.util.TreeSet<>(); void run(Path descriptorSetFile, Path outputRoot) throws IOException, DescriptorValidationException { + run(descriptorSetFile, outputRoot, null); + } + + void run(Path descriptorSetFile, Path outputRoot, Path systemRootsFile) + throws IOException, DescriptorValidationException { Map files = ProtoDescriptorSets.load(descriptorSetFile); + if (systemRootsFile != null) { + for (String line : Files.readAllLines(systemRootsFile, StandardCharsets.UTF_8)) { + if (!line.trim().isEmpty()) systemRoots.add(line.trim()); + } + } List seeds = Arrays.asList( ProtoDescriptorSets.require(files, WORKFLOW_SERVICE_PROTO), ProtoDescriptorSets.require(files, OPERATOR_SERVICE_PROTO)); - this.closure = ProtoClosure.of(seeds); + Map messages = new TreeMap<>(); + for (FileDescriptor file : files.values()) { + for (Descriptor descriptor : file.getMessageTypes()) indexMessages(descriptor, messages); + } + List roots = new ArrayList<>(); + for (String name : systemRoots) { + Descriptor root = messages.get(name); + if (root == null) throw new IllegalStateException("Unknown system Nexus root: " + name); + roots.add(root); + } + this.closure = ProtoClosure.of(seeds, roots); // Deterministic output order, keyed by descriptor full name. Map emitted = new TreeMap<>(); for (Descriptor d : closure.allMessages) { - if (reaches(d)) { + if (reaches(d) || systemRoots.contains(d.getFullName())) { emitted.put(d.getFullName(), d); } } + for (String root : systemRoots) { + if (!emitted.containsKey(root)) + throw new IllegalStateException("Unknown system Nexus root: " + root); + } String source = emit(emitted); Path dir = outputRoot; @@ -122,6 +148,11 @@ void run(Path descriptorSetFile, Path outputRoot) System.out.println("PayloadVisitorGenerator: wrote " + emitted.size() + " visitors to " + out); } + private static void indexMessages(Descriptor descriptor, Map messages) { + messages.put(descriptor.getFullName(), descriptor); + for (Descriptor nested : descriptor.getNestedTypes()) indexMessages(nested, messages); + } + // --- Reachability + classification --- /** Whether {@code d} can transitively contain a payload; delegates to the shared closure. */ @@ -186,9 +217,22 @@ private String emit(Map emitted) { sb.append("final class ").append(OUTPUT_CLASS).append(" {\n"); sb.append(" private ").append(OUTPUT_CLASS).append("() {}\n\n"); + sb.append(" private static Map buildSystemRoots() {\n"); + sb.append(" Map m = new HashMap<>();\n"); + for (String root : systemRoots) { + sb.append(" m.put(\"") + .append(root) + .append("\", REGISTRY.get(\"") + .append(root) + .append("\"));\n"); + } + sb.append(" return m;\n }\n"); + List list = new ArrayList<>(emitted.values()); sb.append(" static final Map REGISTRY = buildRegistry();\n\n"); + sb.append( + " static final Map SYSTEM_ROOTS = buildSystemRoots();\n"); sb.append(" private static Map buildRegistry() {\n"); sb.append(" Map m = new HashMap<>(") .append(Math.max(16, list.size() * 2)) diff --git a/temporal-serviceclient/src/test/java/io/temporal/internal/payload/gen/ProtoClosureRootTest.java b/temporal-serviceclient/src/test/java/io/temporal/internal/payload/gen/ProtoClosureRootTest.java new file mode 100644 index 0000000000..f5913e59bf --- /dev/null +++ b/temporal-serviceclient/src/test/java/io/temporal/internal/payload/gen/ProtoClosureRootTest.java @@ -0,0 +1,54 @@ +package io.temporal.internal.payload.gen; + +import static org.junit.Assert.*; + +import com.google.protobuf.DescriptorProtos.*; +import com.google.protobuf.Descriptors.*; +import io.temporal.api.common.v1.Payload; +import java.util.Arrays; +import java.util.Collections; +import org.junit.Test; + +public class ProtoClosureRootTest { + @Test + public void explicitRootsDiscoverTheirChildrenWithoutServiceSeeds() throws Exception { + String payloadFile = Payload.getDescriptor().getFile().getName(); + FileDescriptor file = + FileDescriptor.buildFrom( + FileDescriptorProto.newBuilder() + .setName("explicit-roots.proto") + .setPackage("temporal.api.test.v1") + .setSyntax("proto3") + .addDependency(payloadFile) + .addMessageType(DescriptorProto.newBuilder().setName("EmptyResponse")) + .addMessageType( + DescriptorProto.newBuilder() + .setName("Request") + .addField( + FieldDescriptorProto.newBuilder() + .setName("child") + .setNumber(1) + .setType(FieldDescriptorProto.Type.TYPE_MESSAGE) + .setTypeName(".temporal.api.test.v1.Child"))) + .addMessageType( + DescriptorProto.newBuilder() + .setName("Child") + .addField( + FieldDescriptorProto.newBuilder() + .setName("payload") + .setNumber(1) + .setType(FieldDescriptorProto.Type.TYPE_MESSAGE) + .setTypeName(".temporal.api.common.v1.Payload"))) + .build(), + new FileDescriptor[] {Payload.getDescriptor().getFile()}); + Descriptor request = file.findMessageTypeByName("Request"); + Descriptor empty = file.findMessageTypeByName("EmptyResponse"); + Descriptor child = file.findMessageTypeByName("Child"); + ProtoClosure closure = ProtoClosure.of(Collections.emptyList(), Arrays.asList(request, empty)); + assertTrue(closure.allMessages.contains(empty)); + assertTrue(closure.allMessages.contains(child)); + assertTrue(closure.reaches(request)); + assertTrue(closure.reaches(child)); + assertFalse(closure.reaches(empty)); + } +} diff --git a/temporal-serviceclient/src/test/java/io/temporal/internal/payload/visitor/SystemNexusPayloadTest.java b/temporal-serviceclient/src/test/java/io/temporal/internal/payload/visitor/SystemNexusPayloadTest.java new file mode 100644 index 0000000000..92def6ebc1 --- /dev/null +++ b/temporal-serviceclient/src/test/java/io/temporal/internal/payload/visitor/SystemNexusPayloadTest.java @@ -0,0 +1,96 @@ +package io.temporal.internal.payload.visitor; + +import static org.junit.Assert.*; + +import com.google.protobuf.ByteString; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.common.v1.Payloads; +import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; +import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import org.junit.Test; + +public class SystemNexusPayloadTest { + private static Payload payload(String value) { + return Payload.newBuilder().setData(ByteString.copyFromUtf8(value)).build(); + } + + @Test + public void visitsNestedSequencesBeforeRepacking() throws Exception { + SignalWithStartWorkflowExecutionRequest request = + SignalWithStartWorkflowExecutionRequest.newBuilder() + .setInput(Payloads.newBuilder().addPayloads(payload("workflow"))) + .setSignalInput(Payloads.newBuilder().addPayloads(payload("signal"))) + .build(); + CompletableFuture> workflow = new CompletableFuture<>(); + Payloads outer = Payloads.newBuilder().addPayloads(SystemNexusPayloads.pack(request)).build(); + CompletableFuture result = + PayloadVisitors.visit( + outer, + PayloadVisitorOptions.newBuilder( + (context, values) -> { + if (values.get(0).getData().toStringUtf8().equals("workflow")) { + return workflow; + } + return CompletableFuture.completedFuture( + Collections.singletonList(payload("SIGNAL"))); + }) + .build()); + assertFalse(result.isDone()); + workflow.complete(Arrays.asList(payload("ONE"), payload("TWO"))); + SignalWithStartWorkflowExecutionRequest decoded = + SignalWithStartWorkflowExecutionRequest.parseFrom(result.join().getPayloads(0).getData()); + assertEquals(2, decoded.getInput().getPayloadsCount()); + assertEquals("SIGNAL", decoded.getSignalInput().getPayloads(0).getData().toStringUtf8()); + assertEquals( + outer.getPayloads(0).getMetadataMap(), result.join().getPayloads(0).getMetadataMap()); + } + + @Test + public void handlesPayloadFreeResponses() { + Payload response = + SystemNexusPayloads.pack( + SignalWithStartWorkflowExecutionResponse.newBuilder().setRunId("run").build()); + Payloads outer = Payloads.newBuilder().addPayloads(response).build(); + assertEquals( + outer, + PayloadVisitors.visit( + outer, + PayloadVisitorOptions.newBuilder( + (context, values) -> { + throw new AssertionError("Outer envelope was visited"); + }) + .build()) + .join()); + } + + @Test + public void rejectsUnknownAndMalformedMarkedPayloads() { + Payload unknown = + SystemNexusPayloads.pack(SignalWithStartWorkflowExecutionRequest.getDefaultInstance()) + .toBuilder() + .putMetadata("messageType", ByteString.copyFromUtf8("unknown.Message")) + .build(); + Payload malformed = + SystemNexusPayloads.pack(SignalWithStartWorkflowExecutionRequest.getDefaultInstance()) + .toBuilder() + .setData(ByteString.copyFrom(new byte[] {(byte) 0xff})) + .build(); + for (Payload value : Arrays.asList(unknown, malformed)) { + CompletionException error = + assertThrows( + CompletionException.class, + () -> + PayloadVisitors.visit( + Payloads.newBuilder().addPayloads(value).build(), + PayloadVisitorOptions.newBuilder( + (context, values) -> CompletableFuture.completedFuture(values)) + .build()) + .join()); + assertTrue(error.getCause() instanceof VisitorException); + } + } +}