From effc7838e0665076bf0e35fcd78b3107afb315f3 Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Tue, 9 Aug 2022 14:30:31 -0400 Subject: [PATCH 001/240] JavaSDK v1.15.0 Release (#334) --- build.gradle | 6 +++--- .../temporal/samples/dsl/DynamicDslWorkflow.java | 15 +++++++-------- .../io/temporal/samples/ssl/SslEnabledWorker.java | 3 +-- .../samples/hello/HelloCancellationScopeTest.java | 2 +- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index f62a387cb..b7bfc0a7c 100644 --- a/build.gradle +++ b/build.gradle @@ -30,8 +30,8 @@ dependencies { implementation(platform("io.opentelemetry:opentelemetry-bom:1.15.0")) implementation(platform("org.junit:junit-bom:5.8.2")) - implementation "io.temporal:temporal-sdk:1.14.0" - implementation "io.temporal:temporal-opentracing:1.14.0" + implementation "io.temporal:temporal-sdk:1.15.0" + implementation "io.temporal:temporal-opentracing:1.15.0" implementation "com.fasterxml.jackson.core:jackson-databind" implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' @@ -59,7 +59,7 @@ dependencies { // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' - testImplementation("io.temporal:temporal-testing:1.14.0") + testImplementation("io.temporal:temporal-testing:1.15.0") testImplementation "junit:junit:4.13.2" testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.6.1' diff --git a/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java b/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java index eb49a6892..1464f5fbe 100644 --- a/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java +++ b/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java @@ -47,10 +47,10 @@ import org.slf4j.Logger; public class DynamicDslWorkflow implements DynamicWorkflow { + private static final Logger logger = Workflow.getLogger(DynamicDslWorkflow.class); private io.serverlessworkflow.api.Workflow dslWorkflow; private WorkflowData workflowData = new WorkflowData(); - private Logger logger = Workflow.getLogger(DynamicDslWorkflow.class); private List queryFunctions; private Map signalMap = new HashMap<>(); @@ -248,12 +248,11 @@ private State executeStateAndReturnNext(State dslWorkflowState) { ChildWorkflowStub childWorkflow = Workflow.newUntypedChildWorkflowStub( action.getSubFlowRef().getWorkflowId(), childWorkflowOptions); - Promise promise = - childWorkflow.executeAsync( - Object.class, - action.getSubFlowRef().getWorkflowId(), - action.getSubFlowRef().getVersion(), - workflowData.getValue()); + childWorkflow.executeAsync( + Object.class, + action.getSubFlowRef().getWorkflowId(), + action.getSubFlowRef().getVersion(), + workflowData.getValue()); // for async we do not care about result in sample // wait until child starts Promise childExecution = @@ -281,7 +280,7 @@ private State executeStateAndReturnNext(State dslWorkflowState) { WorkflowUtils.getFunctionDefinitionsForAction(dslWorkflow, action.getName()); if (functionDefinition.getType().equals(FunctionDefinition.Type.CUSTOM)) { // for this example custom function is assumed sending signal via external stub - String[] operationParts = functionDefinition.getOperation().split("#"); + String[] operationParts = functionDefinition.getOperation().split("#", -1); ExternalWorkflowStub externalWorkflowStub = Workflow.newUntypedExternalWorkflowStub(operationParts[0]); externalWorkflowStub.signal(operationParts[1], workflowData.getValue()); diff --git a/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java b/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java index 925d21e90..94ac07bf1 100644 --- a/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java +++ b/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java @@ -24,7 +24,6 @@ import io.temporal.serviceclient.SimpleSslContextBuilder; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.serviceclient.WorkflowServiceStubsOptions; -import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import java.io.FileInputStream; import java.io.InputStream; @@ -65,7 +64,7 @@ public static void main(String[] args) throws Exception { // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); // Worker that listens on a task queue and hosts both workflow and activity implementations. - Worker worker = factory.newWorker(TASK_QUEUE); + factory.newWorker(TASK_QUEUE); // TODO now register your workflow types and activity implementations. // worker.registerWorkflowImplementationTypes(...); // worker.registerActivitiesImplementations(...); diff --git a/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java b/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java index ce51c9027..1af296fa8 100644 --- a/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java +++ b/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java @@ -39,7 +39,7 @@ public class HelloCancellationScopeTest { .setActivityImplementations(new GreetingActivitiesImpl()) .build(); - @Test(timeout = 200_000) + @Test(timeout = 240_000) public void testActivityImpl() { // Get a workflow stub using the same task queue the worker uses. GreetingWorkflow workflow = From c0a7bd3bf6cdf3cd9c2f10d247c6ed233159c91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Tue, 9 Aug 2022 20:32:13 +0200 Subject: [PATCH 002/240] remove activity registration (#325) --- src/main/java/io/temporal/samples/asyncchild/Starter.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/io/temporal/samples/asyncchild/Starter.java b/src/main/java/io/temporal/samples/asyncchild/Starter.java index 0072fa1fe..21e6d0771 100644 --- a/src/main/java/io/temporal/samples/asyncchild/Starter.java +++ b/src/main/java/io/temporal/samples/asyncchild/Starter.java @@ -25,7 +25,6 @@ import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionResponse; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; -import io.temporal.samples.listworkflows.CustomerActivitiesImpl; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -66,7 +65,6 @@ public static void main(String[] args) { private static void createWorker() { Worker worker = factory.newWorker(TASK_QUEUE); worker.registerWorkflowImplementationTypes(ParentWorkflowImpl.class, ChildWorkflowImpl.class); - worker.registerActivitiesImplementations(new CustomerActivitiesImpl()); factory.start(); } From 49c041e830d7bb5f0bcb96a42a12c00a683440d8 Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Tue, 16 Aug 2022 19:10:05 -0400 Subject: [PATCH 003/240] Rework CryptDataConverter example to use new PayloadCodec (#340) --- ...ryptDataConverter.java => CryptCodec.java} | 172 +++++++----------- .../EncryptedPayloadsActivity.java | 9 +- 2 files changed, 68 insertions(+), 113 deletions(-) rename src/main/java/io/temporal/samples/encryptedpayloads/{CryptDataConverter.java => CryptCodec.java} (51%) diff --git a/src/main/java/io/temporal/samples/encryptedpayloads/CryptDataConverter.java b/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java similarity index 51% rename from src/main/java/io/temporal/samples/encryptedpayloads/CryptDataConverter.java rename to src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java index 3431e660b..e8fc71c7a 100644 --- a/src/main/java/io/temporal/samples/encryptedpayloads/CryptDataConverter.java +++ b/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java @@ -19,25 +19,25 @@ package io.temporal.samples.encryptedpayloads; -import com.google.common.base.Defaults; import com.google.protobuf.ByteString; import io.temporal.api.common.v1.Payload; -import io.temporal.api.common.v1.Payloads; -import io.temporal.common.converter.DataConverter; import io.temporal.common.converter.DataConverterException; -import java.lang.reflect.Type; +import io.temporal.common.converter.EncodingKeys; +import io.temporal.payload.codec.PayloadCodec; +import io.temporal.payload.codec.PayloadCodecException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; -import java.util.Optional; +import java.util.List; +import java.util.stream.Collectors; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; +import org.jetbrains.annotations.NotNull; -public class CryptDataConverter implements DataConverter { - static final String METADATA_ENCODING_KEY = "encoding"; +class CryptCodec implements PayloadCodec { static final ByteString METADATA_ENCODING = ByteString.copyFrom("binary/encrypted", StandardCharsets.UTF_8); @@ -53,10 +53,61 @@ public class CryptDataConverter implements DataConverter { private static final int GCM_TAG_LENGTH_BIT = 128; private static final Charset UTF_8 = StandardCharsets.UTF_8; - private final DataConverter converter; + @NotNull + @Override + public List encode(@NotNull List payloads) { + return payloads.stream().map(this::encodePayload).collect(Collectors.toList()); + } + + @NotNull + @Override + public List decode(@NotNull List payloads) { + return payloads.stream().map(this::decodePayload).collect(Collectors.toList()); + } + + private Payload encodePayload(Payload payload) { + String keyId = getKeyId(); + SecretKey key = getKey(keyId); + + byte[] encryptedData; + try { + encryptedData = encrypt(payload.toByteArray(), key); + } catch (Throwable e) { + throw new DataConverterException(e); + } - public CryptDataConverter(DataConverter converter) { - this.converter = converter; + return Payload.newBuilder() + .putMetadata(EncodingKeys.METADATA_ENCODING_KEY, METADATA_ENCODING) + .putMetadata(METADATA_ENCRYPTION_CIPHER_KEY, METADATA_ENCRYPTION_CIPHER) + .putMetadata(METADATA_ENCRYPTION_KEY_ID_KEY, ByteString.copyFromUtf8(keyId)) + .setData(ByteString.copyFrom(encryptedData)) + .build(); + } + + private Payload decodePayload(Payload payload) { + if (METADATA_ENCODING.equals( + payload.getMetadataOrDefault(EncodingKeys.METADATA_ENCODING_KEY, null))) { + String keyId; + try { + keyId = payload.getMetadataOrThrow(METADATA_ENCRYPTION_KEY_ID_KEY).toString(UTF_8); + } catch (Exception e) { + throw new PayloadCodecException(e); + } + SecretKey key = getKey(keyId); + + byte[] plainData; + Payload decryptedPayload; + + try { + plainData = decrypt(payload.getData().toByteArray(), key); + decryptedPayload = Payload.parseFrom(plainData); + return decryptedPayload; + } catch (Throwable e) { + throw new PayloadCodecException(e); + } + } else { + return payload; + } } private String getKeyId() { @@ -106,105 +157,4 @@ private byte[] decrypt(byte[] encryptedDataWithNonce, SecretKey key) throws Exce return cipher.doFinal(encryptedData); } - - @Override - public Optional toPayload(T value) throws DataConverterException { - return converter.toPayload(value); - } - - public Optional toEncryptedPayload(T value) throws DataConverterException { - Optional optionalPayload = converter.toPayload(value); - - if (!optionalPayload.isPresent()) { - return optionalPayload; - } - - Payload innerPayload = optionalPayload.get(); - - String keyId = getKeyId(); - SecretKey key = getKey(keyId); - - byte[] encryptedData; - try { - encryptedData = encrypt(innerPayload.toByteArray(), key); - } catch (Throwable e) { - throw new DataConverterException(e); - } - - Payload encryptedPayload = - Payload.newBuilder() - .putMetadata(METADATA_ENCODING_KEY, METADATA_ENCODING) - .putMetadata(METADATA_ENCRYPTION_CIPHER_KEY, METADATA_ENCRYPTION_CIPHER) - .putMetadata(METADATA_ENCRYPTION_KEY_ID_KEY, ByteString.copyFromUtf8(keyId)) - .setData(ByteString.copyFrom(encryptedData)) - .build(); - - return Optional.of(encryptedPayload); - } - - @Override - public T fromPayload(Payload payload, Class valueClass, Type valueType) { - ByteString encoding = payload.getMetadataOrDefault(METADATA_ENCODING_KEY, null); - if (!encoding.equals(METADATA_ENCODING)) { - return converter.fromPayload(payload, valueClass, valueType); - } - - String keyId; - try { - keyId = payload.getMetadataOrThrow(METADATA_ENCRYPTION_KEY_ID_KEY).toString(UTF_8); - } catch (Exception e) { - throw new DataConverterException(payload, valueClass, e); - } - SecretKey key = getKey(keyId); - - byte[] plainData; - Payload decryptedPayload; - - try { - plainData = decrypt(payload.getData().toByteArray(), key); - decryptedPayload = Payload.parseFrom(plainData); - } catch (Throwable e) { - throw new DataConverterException(e); - } - - return converter.fromPayload(decryptedPayload, valueClass, valueType); - } - - @Override - public Optional toPayloads(Object... values) throws DataConverterException { - if (values == null || values.length == 0) { - return Optional.empty(); - } - try { - Payloads.Builder result = Payloads.newBuilder(); - for (Object value : values) { - Optional payload = toEncryptedPayload(value); - if (payload.isPresent()) { - result.addPayloads(payload.get()); - } else { - result.addPayloads(Payload.getDefaultInstance()); - } - } - return Optional.of(result.build()); - } catch (DataConverterException e) { - throw e; - } catch (Throwable e) { - throw new DataConverterException(e); - } - } - - @Override - public T fromPayloads( - int index, Optional content, Class parameterType, Type genericParameterType) - throws DataConverterException { - if (!content.isPresent()) { - return (T) Defaults.defaultValue((Class) parameterType); - } - int count = content.get().getPayloadsCount(); - // To make adding arguments a backwards compatible change - if (index >= count) { - return (T) Defaults.defaultValue((Class) parameterType); - } - return fromPayload(content.get().getPayloads(index), parameterType, genericParameterType); - } } diff --git a/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java b/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java index fd1339cd6..88c8a1d78 100644 --- a/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java +++ b/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java @@ -25,7 +25,8 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowOptions; -import io.temporal.common.converter.DataConverter; +import io.temporal.common.converter.CodecDataConverter; +import io.temporal.common.converter.DefaultDataConverter; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -33,6 +34,7 @@ import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; import java.time.Duration; +import java.util.Collections; /** * Hello World Temporal workflow that executes a single activity. Requires a local instance the @@ -91,7 +93,10 @@ public static void main(String[] args) { WorkflowClient.newInstance( service, WorkflowClientOptions.newBuilder() - .setDataConverter(new CryptDataConverter(DataConverter.getDefaultInstance())) + .setDataConverter( + new CodecDataConverter( + DefaultDataConverter.newDefaultInstance(), + Collections.singletonList(new CryptCodec()))) .build()); // worker factory that can be used to create workers for specific task queues From 33aec8da32b213afc81c690ae9fce67ad72bdbdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 12:15:18 -0400 Subject: [PATCH 004/240] Bump junit-bom from 5.8.2 to 5.9.0 (#330) Bumps [junit-bom](https://github.com/junit-team/junit5) from 5.8.2 to 5.9.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.2...r5.9.0) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b7bfc0a7c..4e8cbf8cf 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ repositories { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.3")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.15.0")) - implementation(platform("org.junit:junit-bom:5.8.2")) + implementation(platform("org.junit:junit-bom:5.9.0")) implementation "io.temporal:temporal-sdk:1.15.0" implementation "io.temporal:temporal-opentracing:1.15.0" From 0b6b67a1ab58221fdf21937ec6f3dc467a8583a0 Mon Sep 17 00:00:00 2001 From: Jay Vercellone Date: Tue, 6 Sep 2022 09:16:23 -0700 Subject: [PATCH 005/240] Improve references to workflow definition files (#332) * Improve references to workflow definition files * Update extension of referenced files to match the currently existing ones * Transform the file references into an enumerated list with links to the corresponding files * Add link to the Serverless Workflow site --- src/main/java/io/temporal/samples/dsl/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/temporal/samples/dsl/README.md b/src/main/java/io/temporal/samples/dsl/README.md index 9d1cf87df..838849595 100644 --- a/src/main/java/io/temporal/samples/dsl/README.md +++ b/src/main/java/io/temporal/samples/dsl/README.md @@ -6,12 +6,15 @@ The sample uses CNCF Serverless Workflow (serverlessworkflow.io) DSL and its Jav which helps us parse the DSL into an object model as well as provides DSL validation. Since this is just a sample, this sample provides only partial implementation of the -entire Serverless Workflow DSL features. +entire [Serverless Workflow](https://serverlessworkflow.io/) DSL features. -This sample runs the following DSL workflows, `customerapplication/workflow.yml`, -`bankingtransactions/workflow.yml`, `customerapproval/applicantworkflow.yml`, -`customerapproval/approvalworkflow.yml`, `bankingtransactionssubflow/parentworkflow.json`, -`bankingtransactionssubflow/childworkflow.yml`. +This sample runs the following DSL workflows: +1. [`customerapplication/workflow.yml`](/src/main/resources/dsl/customerapplication/workflow.yml) +2. [`bankingtransactions/workflow.yml`](/src/main/resources/dsl/bankingtransactions/workflow.yml) +3. [`customerapproval/applicantworkflow.json`](/src/main/resources/dsl/customerapproval/applicantworkflow.json) +4. [`customerapproval/approvalworkflow.json`](/src/main/resources/dsl/customerapproval/approvalworkflow.json) +5. [`bankingtransactionssubflow/parentworkflow.json`](/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json) +6. [`bankingtransactionssubflow/childworkflow.json`](/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json) Note that most DSLs, including Serverless Workflow DSL used in this sample represent their workflow data as JSON. As such manipulation of this data is done via expression languages From 59db2c3aed69d19c8d98d53db9018ffb0663a289 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 12:33:35 -0400 Subject: [PATCH 006/240] Bump opentelemetry-bom from 1.15.0 to 1.17.0 (#338) Bumps [opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.15.0 to 1.17.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.15.0...v1.17.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4e8cbf8cf..d165b0e7a 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ repositories { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.3")) - implementation(platform("io.opentelemetry:opentelemetry-bom:1.15.0")) + implementation(platform("io.opentelemetry:opentelemetry-bom:1.17.0")) implementation(platform("org.junit:junit-bom:5.9.0")) implementation "io.temporal:temporal-sdk:1.15.0" From c7f6592ef891c2108108afcd2de5a12cd80fd1a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 12:41:28 -0400 Subject: [PATCH 007/240] Bump cloudevents-json-jackson from 2.3.0 to 2.4.0 (#344) Bumps cloudevents-json-jackson from 2.3.0 to 2.4.0. --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-json-jackson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d165b0e7a..cd2a209cf 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ dependencies { implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.3.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.3.0' - implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.3.0' + implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' From 950a3e554828c860c4bf426a64af37921548b48b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 12:46:02 -0400 Subject: [PATCH 008/240] Bump cloudevents-api from 2.3.0 to 2.4.0 (#345) Bumps [cloudevents-api](https://github.com/cloudevents/sdk-java) from 2.3.0 to 2.4.0. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.3.0...2.4.0) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cd2a209cf..ee3021849 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.3.0' - implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.3.0' + implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.0' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' From 8b10bc193b0752b0016eaec887e5854120ba87cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 12:50:41 -0400 Subject: [PATCH 009/240] Bump cloudevents-core from 2.3.0 to 2.4.0 (#350) Bumps [cloudevents-core](https://github.com/cloudevents/sdk-java) from 2.3.0 to 2.4.0. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.3.0...2.4.0) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ee3021849..3edb6de44 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ dependencies { implementation "com.fasterxml.jackson.core:jackson-databind" implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' - implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.3.0' + implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.0' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' From 4d9a969adfdfbeeacfa4715183e4713ae2975203 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 12:51:23 -0400 Subject: [PATCH 010/240] Bump jackson-bom from 2.13.3 to 2.13.4 (#346) Bumps [jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.13.3 to 2.13.4. - [Release notes](https://github.com/FasterXML/jackson-bom/releases) - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.13.3...jackson-bom-2.13.4) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3edb6de44..a203d82dc 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ repositories { } dependencies { - implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.3")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.4")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.17.0")) implementation(platform("org.junit:junit-bom:5.9.0")) From 65fe388560817c008c4dde2eae56c8dc42d0d400 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 12:55:23 -0400 Subject: [PATCH 011/240] Bump mockito-core from 4.6.1 to 4.7.0 (#348) Bumps [mockito-core](https://github.com/mockito/mockito) from 4.6.1 to 4.7.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.6.1...v4.7.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a203d82dc..f85b2f291 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:1.15.0") testImplementation "junit:junit:4.13.2" - testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.6.1' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.7.0' testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' testImplementation "org.junit.jupiter:junit-jupiter-api" From c80fa1390b95742b02765db3331485d564271985 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 6 Sep 2022 13:58:54 -0400 Subject: [PATCH 012/240] Update SDK to 1.16.0 (#353) Signed-off-by: Tihomir Surdilovic Signed-off-by: Tihomir Surdilovic --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index f85b2f291..2eecbcbeb 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ dependencies { implementation(platform("io.opentelemetry:opentelemetry-bom:1.17.0")) implementation(platform("org.junit:junit-bom:5.9.0")) - implementation "io.temporal:temporal-sdk:1.15.0" + implementation "io.temporal:temporal-sdk:1.16.0" implementation "io.temporal:temporal-opentracing:1.15.0" implementation "com.fasterxml.jackson.core:jackson-databind" @@ -59,7 +59,7 @@ dependencies { // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' - testImplementation("io.temporal:temporal-testing:1.15.0") + testImplementation("io.temporal:temporal-testing:1.16.0") testImplementation "junit:junit:4.13.2" testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.7.0' From c3de6bfb278068be91ebffed160f706872531e7c Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 6 Sep 2022 14:09:08 -0400 Subject: [PATCH 013/240] fix 1.16 opentracing module (#354) Signed-off-by: Tihomir Surdilovic Signed-off-by: Tihomir Surdilovic --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2eecbcbeb..73c569da3 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ dependencies { implementation(platform("org.junit:junit-bom:5.9.0")) implementation "io.temporal:temporal-sdk:1.16.0" - implementation "io.temporal:temporal-opentracing:1.15.0" + implementation "io.temporal:temporal-opentracing:1.16.0" implementation "com.fasterxml.jackson.core:jackson-databind" implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' From 452e2836bfc4db6258aaa3ec390b7dca98fd21df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Tue, 6 Sep 2022 20:11:09 +0200 Subject: [PATCH 014/240] Added test that verified custom metrics published by users (#335) * added test testCountActivityRetriesMetric * replaced invocation to deprecated methods * removed internal classes usage --- .../samples/metrics/MetricsStarter.java | 2 +- .../samples/metrics/MetricsWorker.java | 2 +- .../temporal/samples/metrics/MetricsTest.java | 160 ++++++++++++++++++ 3 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 src/test/java/io/temporal/samples/metrics/MetricsTest.java diff --git a/src/main/java/io/temporal/samples/metrics/MetricsStarter.java b/src/main/java/io/temporal/samples/metrics/MetricsStarter.java index 7df16a176..bc31e3238 100644 --- a/src/main/java/io/temporal/samples/metrics/MetricsStarter.java +++ b/src/main/java/io/temporal/samples/metrics/MetricsStarter.java @@ -58,7 +58,7 @@ public static void main(String[] args) { WorkflowServiceStubsOptions stubOptions = WorkflowServiceStubsOptions.newBuilder().setMetricsScope(scope).build(); - WorkflowServiceStubs service = WorkflowServiceStubs.newInstance(stubOptions); + WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(stubOptions); WorkflowClient client = WorkflowClient.newInstance(service); WorkflowOptions workflowOptions = diff --git a/src/main/java/io/temporal/samples/metrics/MetricsWorker.java b/src/main/java/io/temporal/samples/metrics/MetricsWorker.java index 68e29b17a..258a0d689 100644 --- a/src/main/java/io/temporal/samples/metrics/MetricsWorker.java +++ b/src/main/java/io/temporal/samples/metrics/MetricsWorker.java @@ -64,7 +64,7 @@ public static void main(String[] args) { WorkflowServiceStubsOptions stubOptions = WorkflowServiceStubsOptions.newBuilder().setMetricsScope(scope).build(); - WorkflowServiceStubs service = WorkflowServiceStubs.newInstance(stubOptions); + WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(stubOptions); WorkflowClient client = WorkflowClient.newInstance(service); WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/src/test/java/io/temporal/samples/metrics/MetricsTest.java b/src/test/java/io/temporal/samples/metrics/MetricsTest.java new file mode 100644 index 000000000..4c593cb8a --- /dev/null +++ b/src/test/java/io/temporal/samples/metrics/MetricsTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.metrics; + +import static junit.framework.TestCase.assertEquals; + +import com.google.common.collect.ImmutableMap; +import com.uber.m3.tally.RootScopeBuilder; +import com.uber.m3.tally.Scope; +import com.uber.m3.tally.StatsReporter; +import com.uber.m3.util.Duration; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.ImmutableTag; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.reporter.MicrometerClientStatsReporter; +import io.temporal.samples.metrics.activities.MetricsActivitiesImpl; +import io.temporal.samples.metrics.workflow.MetricsWorkflow; +import io.temporal.samples.metrics.workflow.MetricsWorkflowImpl; +import io.temporal.serviceclient.MetricsTag; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.testing.TestWorkflowRule; +import io.temporal.worker.WorkerOptions; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.jetbrains.annotations.NotNull; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class MetricsTest { + + private static final long REPORTING_FLUSH_TIME = 50; + private static List TAGS_NAMESPACE_QUEUE; + private final String SDK_CUSTOM_KEY = "sdkCustomTag1Key"; + private final String SDK_CUSTOM_VALUE = "sdkCustomTag1Value"; + private final SimpleMeterRegistry registry = new SimpleMeterRegistry(); + private final StatsReporter reporter = new MicrometerClientStatsReporter(registry); + private final Scope metricsScope = + new RootScopeBuilder() + .tags(ImmutableMap.of(SDK_CUSTOM_KEY, SDK_CUSTOM_VALUE)) + .reporter(reporter) + .reportEvery(Duration.ofMillis(REPORTING_FLUSH_TIME >> 1)); + private final String TEST_NAMESPACE = "UnitTest"; + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(MetricsWorkflowImpl.class) + .setMetricsScope(metricsScope) + .setWorkerOptions(WorkerOptions.newBuilder().build()) + .setActivityImplementations(new MetricsActivitiesImpl()) + .build(); + + private WorkflowServiceStubs clientStubs; + private WorkflowClient workflowClient; + + private static List replaceTags(List tags, String... nameValuePairs) { + for (int i = 0; i < nameValuePairs.length; i += 2) { + tags = replaceTag(tags, nameValuePairs[i], nameValuePairs[i + 1]); + } + return tags; + } + + private static List replaceTag(List tags, String name, String value) { + List result = + tags.stream().filter(tag -> !name.equals(tag.getKey())).collect(Collectors.toList()); + result.add(new ImmutableTag(name, value)); + return result; + } + + @Before + public void setUp() { + + final WorkflowServiceStubsOptions options = + testWorkflowRule.getWorkflowClient().getWorkflowServiceStubs().getOptions(); + + this.clientStubs = WorkflowServiceStubs.newServiceStubs(options); + + this.workflowClient = + WorkflowClient.newInstance(clientStubs, testWorkflowRule.getWorkflowClient().getOptions()); + + final Map stringStringMap = MetricsTag.defaultTags(TEST_NAMESPACE); + final List TAGS_NAMESPACE = + stringStringMap.entrySet().stream() + .map( + nameValueEntry -> + new ImmutableTag(nameValueEntry.getKey(), nameValueEntry.getValue())) + .collect(Collectors.toList()); + + TAGS_NAMESPACE_QUEUE = + replaceTags(TAGS_NAMESPACE, MetricsTag.TASK_QUEUE, testWorkflowRule.getTaskQueue()); + } + + @After + public void tearDown() { + this.clientStubs.shutdownNow(); + this.registry.close(); + } + + @Test + public void testCountActivityRetriesMetric() throws InterruptedException { + final MetricsWorkflow metricsWorkflow = + workflowClient.newWorkflowStub( + MetricsWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .validateBuildWithDefaults()); + + metricsWorkflow.exec("hello metrics"); + + Thread.sleep(REPORTING_FLUSH_TIME); + + assertIntCounter(4, countMetricActivityRetriesForActivity("PerformB")); + + assertIntCounter(2, countMetricActivityRetriesForActivity("PerformA")); + } + + @NotNull + private Counter countMetricActivityRetriesForActivity(String performB) { + final List tags = + replaceTags( + TAGS_NAMESPACE_QUEUE, + MetricsTag.ACTIVITY_TYPE, + performB, + MetricsTag.WORKFLOW_TYPE, + "MetricsWorkflow", + MetricsTag.WORKER_TYPE, + "ActivityWorker", + SDK_CUSTOM_KEY, + SDK_CUSTOM_VALUE); + return registry.counter("activity_retries", tags); + } + + private void assertIntCounter(int expectedValue, Counter counter) { + assertEquals(expectedValue, Math.round(counter.count())); + } +} From 680846f7d161ef3e6f92d33ed41fce470f1c4a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Tue, 6 Sep 2022 20:17:57 +0200 Subject: [PATCH 015/240] add hello child test with junit 5 (#342) --- .../samples/hello/HelloChildJUnit5Test.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java diff --git a/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java b/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java new file mode 100644 index 000000000..61914a87e --- /dev/null +++ b/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static org.mockito.Mockito.*; + +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.Assert; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +/** Unit test for {@link HelloChild}. Doesn't use an external Temporal service. */ +public class HelloChildJUnit5Test { + + @RegisterExtension + public static final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + .setWorkflowTypes(HelloChild.GreetingWorkflowImpl.class) + .setDoNotStart(true) + .build(); + + @Test + public void testMockedChild( + TestWorkflowEnvironment testEnv, Worker worker, HelloChild.GreetingWorkflow workflow) { + + // As new mock is created on each workflow task the only last one is useful to verify calls. + AtomicReference lastChildMock = new AtomicReference<>(); + // Factory is called to create a new workflow object on each workflow task. + worker.addWorkflowImplementationFactory( + HelloChild.GreetingChild.class, + () -> { + HelloChild.GreetingChild child = mock(HelloChild.GreetingChild.class); + when(child.composeGreeting("Hello", "World")).thenReturn("Bye World!"); + lastChildMock.set(child); + return child; + }); + + testEnv.start(); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.getGreeting("World"); + Assert.assertEquals("Bye World!", greeting); + HelloChild.GreetingChild mock = lastChildMock.get(); + verify(mock).composeGreeting(eq("Hello"), eq("World")); + + testEnv.shutdown(); + } +} From c4f81e0621c546a9df656a0b41eb9f1b4907f5b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Fri, 30 Sep 2022 16:12:04 +0200 Subject: [PATCH 016/240] added client interceptor (#361) --- .../samples/interceptor/ClientCounter.java | 112 ++++++++++++++++++ .../interceptor/InterceptorStarter.java | 24 +++- .../io/temporal/samples/interceptor/README.md | 4 +- .../SimpleClientCallsInterceptor.java | 58 +++++++++ .../interceptor/SimpleClientInterceptor.java | 38 ++++++ ...eCountActivityInboundCallsInterceptor.java | 4 +- ...eCountWorkflowInboundCallsInterceptor.java | 6 +- ...CountWorkflowOutboundCallsInterceptor.java | 3 +- .../{Counter.java => WorkerCounter.java} | 2 +- .../ClientCountInterceptorTest.java | 91 ++++++++++++++ ...t.java => WorkerCountInterceptorTest.java} | 14 +-- 11 files changed, 335 insertions(+), 21 deletions(-) create mode 100644 src/main/java/io/temporal/samples/interceptor/ClientCounter.java create mode 100644 src/main/java/io/temporal/samples/interceptor/SimpleClientCallsInterceptor.java create mode 100644 src/main/java/io/temporal/samples/interceptor/SimpleClientInterceptor.java rename src/main/java/io/temporal/samples/interceptor/{Counter.java => WorkerCounter.java} (99%) create mode 100644 src/test/java/io/temporal/samples/interceptor/ClientCountInterceptorTest.java rename src/test/java/io/temporal/samples/interceptor/{CountInterceptorTest.java => WorkerCountInterceptorTest.java} (86%) diff --git a/src/main/java/io/temporal/samples/interceptor/ClientCounter.java b/src/main/java/io/temporal/samples/interceptor/ClientCounter.java new file mode 100644 index 000000000..9a80d08cf --- /dev/null +++ b/src/main/java/io/temporal/samples/interceptor/ClientCounter.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.interceptor; + +import java.util.AbstractMap; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** Simple counter class. */ +public class ClientCounter { + private static final String NUM_OF_GET_RESULT = "numOfGetResult"; + private static final String NUM_OF_WORKFLOW_EXECUTIONS = "numOfWorkflowExec"; + private static final String NUM_OF_SIGNALS = "numOfSignals"; + private static final String NUM_OF_QUERIES = "numOfQueries"; + private static final Map> perWorkflowIdMap = + Collections.synchronizedMap(new HashMap<>()); + + public String getInfo() { + StringBuilder stringBuilder = new StringBuilder(); + for (String workflowRunId : perWorkflowIdMap.keySet()) { + stringBuilder.append("\n** Workflow ID: " + workflowRunId); + Map info = perWorkflowIdMap.get(workflowRunId); + stringBuilder.append( + "\n\tTotal Number of Workflow Exec: " + info.get(NUM_OF_WORKFLOW_EXECUTIONS)); + stringBuilder.append("\n\tTotal Number of Signals: " + info.get(NUM_OF_SIGNALS)); + stringBuilder.append("\n\tTotal Number of Queries: " + info.get(NUM_OF_QUERIES)); + stringBuilder.append("\n\tTotal Number of GetResult: " + info.get(NUM_OF_GET_RESULT)); + } + + return stringBuilder.toString(); + } + + private void add(String workflowId, String type) { + if (!perWorkflowIdMap.containsKey(workflowId)) { + perWorkflowIdMap.put(workflowId, getDefaultInfoMap()); + } + + if (perWorkflowIdMap.get(workflowId).get(type) == null) { + perWorkflowIdMap.get(workflowId).put(type, 1); + } else { + int current = perWorkflowIdMap.get(workflowId).get(type).intValue(); + int next = current + 1; + perWorkflowIdMap.get(workflowId).put(type, next); + } + } + + public int getNumOfWorkflowExecutions(String workflowId) { + return perWorkflowIdMap.get(workflowId).get(NUM_OF_WORKFLOW_EXECUTIONS); + } + + public int getNumOfGetResults(String workflowId) { + return perWorkflowIdMap.get(workflowId).get(NUM_OF_GET_RESULT); + } + + public int getNumOfSignals(String workflowId) { + return perWorkflowIdMap.get(workflowId).get(NUM_OF_SIGNALS); + } + + public int getNumOfQueries(String workflowId) { + return perWorkflowIdMap.get(workflowId).get(NUM_OF_QUERIES); + } + + /** + * Creates a default counter info map for a workflowid + * + * @return default counter info map + */ + private Map getDefaultInfoMap() { + return Stream.of( + new AbstractMap.SimpleImmutableEntry<>(NUM_OF_WORKFLOW_EXECUTIONS, 0), + new AbstractMap.SimpleImmutableEntry<>(NUM_OF_SIGNALS, 0), + new AbstractMap.SimpleImmutableEntry<>(NUM_OF_GET_RESULT, 0), + new AbstractMap.SimpleImmutableEntry<>(NUM_OF_QUERIES, 0)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + public void addStartInvocation(String workflowId) { + add(workflowId, NUM_OF_WORKFLOW_EXECUTIONS); + } + + public void addSignalInvocation(String workflowId) { + add(workflowId, NUM_OF_SIGNALS); + } + + public void addGetResultInvocation(String workflowId) { + add(workflowId, NUM_OF_GET_RESULT); + } + + public void addQueryInvocation(String workflowId) { + add(workflowId, NUM_OF_QUERIES); + } +} diff --git a/src/main/java/io/temporal/samples/interceptor/InterceptorStarter.java b/src/main/java/io/temporal/samples/interceptor/InterceptorStarter.java index ba81a230e..4ebb0b7df 100644 --- a/src/main/java/io/temporal/samples/interceptor/InterceptorStarter.java +++ b/src/main/java/io/temporal/samples/interceptor/InterceptorStarter.java @@ -20,8 +20,10 @@ package io.temporal.samples.interceptor; import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.common.interceptors.WorkflowClientInterceptor; import io.temporal.samples.interceptor.activities.MyActivitiesImpl; import io.temporal.samples.interceptor.workflow.MyChildWorkflowImpl; import io.temporal.samples.interceptor.workflow.MyWorkflow; @@ -35,19 +37,25 @@ public class InterceptorStarter { - public static SimpleCountWorkerInterceptor interceptor = new SimpleCountWorkerInterceptor(); + public static SimpleCountWorkerInterceptor workerInterceptor = new SimpleCountWorkerInterceptor(); private static final String TEST_QUEUE = "test-queue"; private static final String WORKFLOW_ID = "TestInterceptorWorkflow"; private static final Logger logger = LoggerFactory.getLogger(SimpleCountWorkerInterceptor.class); public static void main(String[] args) { + + final ClientCounter clientCounter = new ClientCounter(); + final WorkflowClientInterceptor clientInterceptor = new SimpleClientInterceptor(clientCounter); + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = + WorkflowClient.newInstance( + service, WorkflowClientOptions.newBuilder().setInterceptors(clientInterceptor).build()); WorkerFactoryOptions wfo = WorkerFactoryOptions.newBuilder() - .setWorkerInterceptors(interceptor) + .setWorkerInterceptors(workerInterceptor) .validateAndBuildWithDefaults(); WorkerFactory factory = WorkerFactory.newInstance(client, wfo); @@ -84,9 +92,13 @@ public static void main(String[] args) { logger.info("Name: " + name); logger.info("Title: " + title); - // Print the Counter Info - logger.info("Collected Counter Info: "); - logger.info(Counter.getInfo()); + // Print the Worker Counter Info + logger.info("Collected Worker Counter Info: "); + logger.info(WorkerCounter.getInfo()); + + // Print the Client Counter Info + logger.info("Collected Client Counter Info: "); + logger.info(clientCounter.getInfo()); System.exit(0); } diff --git a/src/main/java/io/temporal/samples/interceptor/README.md b/src/main/java/io/temporal/samples/interceptor/README.md index a08f8ee09..1c5860b95 100644 --- a/src/main/java/io/temporal/samples/interceptor/README.md +++ b/src/main/java/io/temporal/samples/interceptor/README.md @@ -1,6 +1,8 @@ # Demo Workflow Interceptor -The sample demonstrates the use of a simple Workflow Interceptor that counts the number of Workflow Executions, Child Workflow Executions, and Activity Executions as well as the number of Signals and Queries. +The sample demonstrates: +- the use of a simple Worker Workflow Interceptor that counts the number of Workflow Executions, Child Workflow Executions, and Activity Executions as well as the number of Signals and Queries. +- the use of a simple Client Workflow Interceptor that counts the number of Workflow Executions as well as the number of Signals, Queries and GetResult invocations. Run the following command to start the sample: diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleClientCallsInterceptor.java b/src/main/java/io/temporal/samples/interceptor/SimpleClientCallsInterceptor.java new file mode 100644 index 000000000..1b5a40973 --- /dev/null +++ b/src/main/java/io/temporal/samples/interceptor/SimpleClientCallsInterceptor.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.interceptor; + +import io.temporal.common.interceptors.WorkflowClientCallsInterceptor; +import io.temporal.common.interceptors.WorkflowClientCallsInterceptorBase; +import java.util.concurrent.TimeoutException; + +public class SimpleClientCallsInterceptor extends WorkflowClientCallsInterceptorBase { + private ClientCounter clientCounter; + + public SimpleClientCallsInterceptor( + WorkflowClientCallsInterceptor next, ClientCounter clientCounter) { + super(next); + this.clientCounter = clientCounter; + } + + @Override + public WorkflowStartOutput start(WorkflowStartInput input) { + clientCounter.addStartInvocation(input.getWorkflowId()); + return super.start(input); + } + + @Override + public WorkflowSignalOutput signal(WorkflowSignalInput input) { + clientCounter.addSignalInvocation(input.getWorkflowExecution().getWorkflowId()); + return super.signal(input); + } + + @Override + public GetResultOutput getResult(GetResultInput input) throws TimeoutException { + clientCounter.addGetResultInvocation(input.getWorkflowExecution().getWorkflowId()); + return super.getResult(input); + } + + @Override + public QueryOutput query(QueryInput input) { + clientCounter.addQueryInvocation(input.getWorkflowExecution().getWorkflowId()); + return super.query(input); + } +} diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleClientInterceptor.java b/src/main/java/io/temporal/samples/interceptor/SimpleClientInterceptor.java new file mode 100644 index 000000000..bfdec3a47 --- /dev/null +++ b/src/main/java/io/temporal/samples/interceptor/SimpleClientInterceptor.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.interceptor; + +import io.temporal.common.interceptors.WorkflowClientCallsInterceptor; +import io.temporal.common.interceptors.WorkflowClientInterceptorBase; + +public class SimpleClientInterceptor extends WorkflowClientInterceptorBase { + + private ClientCounter clientCounter; + + public SimpleClientInterceptor(ClientCounter clientCounter) { + this.clientCounter = clientCounter; + } + + @Override + public WorkflowClientCallsInterceptor workflowClientCallsInterceptor( + WorkflowClientCallsInterceptor next) { + return new SimpleClientCallsInterceptor(next, clientCounter); + } +} diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleCountActivityInboundCallsInterceptor.java b/src/main/java/io/temporal/samples/interceptor/SimpleCountActivityInboundCallsInterceptor.java index 370f72921..5e340da92 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleCountActivityInboundCallsInterceptor.java +++ b/src/main/java/io/temporal/samples/interceptor/SimpleCountActivityInboundCallsInterceptor.java @@ -40,9 +40,9 @@ public void init(ActivityExecutionContext context) { @Override public ActivityOutput execute(ActivityInput input) { - Counter.add( + WorkerCounter.add( this.activityExecutionContext.getInfo().getWorkflowId(), - Counter.NUM_OF_ACTIVITY_EXECUTIONS); + WorkerCounter.NUM_OF_ACTIVITY_EXECUTIONS); return super.execute(input); } } diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowInboundCallsInterceptor.java b/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowInboundCallsInterceptor.java index 34e4e34ee..c1c6db29c 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowInboundCallsInterceptor.java +++ b/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowInboundCallsInterceptor.java @@ -42,19 +42,19 @@ public void init(WorkflowOutboundCallsInterceptor outboundCalls) { @Override public WorkflowOutput execute(WorkflowInput input) { - Counter.add(this.workflowInfo.getWorkflowId(), Counter.NUM_OF_WORKFLOW_EXECUTIONS); + WorkerCounter.add(this.workflowInfo.getWorkflowId(), WorkerCounter.NUM_OF_WORKFLOW_EXECUTIONS); return super.execute(input); } @Override public void handleSignal(SignalInput input) { - Counter.add(this.workflowInfo.getWorkflowId(), Counter.NUM_OF_SIGNALS); + WorkerCounter.add(this.workflowInfo.getWorkflowId(), WorkerCounter.NUM_OF_SIGNALS); super.handleSignal(input); } @Override public QueryOutput handleQuery(QueryInput input) { - Counter.add(this.workflowInfo.getWorkflowId(), Counter.NUM_OF_QUERIES); + WorkerCounter.add(this.workflowInfo.getWorkflowId(), WorkerCounter.NUM_OF_QUERIES); return super.handleQuery(input); } } diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowOutboundCallsInterceptor.java b/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowOutboundCallsInterceptor.java index 7202b8ff1..0b2997109 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowOutboundCallsInterceptor.java +++ b/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowOutboundCallsInterceptor.java @@ -32,7 +32,8 @@ public SimpleCountWorkflowOutboundCallsInterceptor(WorkflowOutboundCallsIntercep @Override public ChildWorkflowOutput executeChildWorkflow(ChildWorkflowInput input) { - Counter.add(Workflow.getInfo().getWorkflowId(), Counter.NUM_OF_CHILD_WORKFLOW_EXECUTIONS); + WorkerCounter.add( + Workflow.getInfo().getWorkflowId(), WorkerCounter.NUM_OF_CHILD_WORKFLOW_EXECUTIONS); return super.executeChildWorkflow(input); } } diff --git a/src/main/java/io/temporal/samples/interceptor/Counter.java b/src/main/java/io/temporal/samples/interceptor/WorkerCounter.java similarity index 99% rename from src/main/java/io/temporal/samples/interceptor/Counter.java rename to src/main/java/io/temporal/samples/interceptor/WorkerCounter.java index e6a2934c7..86e01cc4b 100644 --- a/src/main/java/io/temporal/samples/interceptor/Counter.java +++ b/src/main/java/io/temporal/samples/interceptor/WorkerCounter.java @@ -30,7 +30,7 @@ * Simple counter class. Static impl just for the sake of the sample. Note: in your applications you * should use CDI for example instead. */ -public class Counter { +public class WorkerCounter { private static Map> perWorkflowIdMap = Collections.synchronizedMap(new HashMap<>()); diff --git a/src/test/java/io/temporal/samples/interceptor/ClientCountInterceptorTest.java b/src/test/java/io/temporal/samples/interceptor/ClientCountInterceptorTest.java new file mode 100644 index 000000000..c6f9a6baf --- /dev/null +++ b/src/test/java/io/temporal/samples/interceptor/ClientCountInterceptorTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.interceptor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.samples.interceptor.activities.MyActivitiesImpl; +import io.temporal.samples.interceptor.workflow.MyChildWorkflowImpl; +import io.temporal.samples.interceptor.workflow.MyWorkflow; +import io.temporal.samples.interceptor.workflow.MyWorkflowImpl; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Rule; +import org.junit.Test; + +public class ClientCountInterceptorTest { + + private static final String WORKFLOW_ID = "TestInterceptorWorkflow"; + + private final ClientCounter clientCounter = new ClientCounter(); + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(MyWorkflowImpl.class, MyChildWorkflowImpl.class) + .setActivityImplementations(new MyActivitiesImpl()) + .setWorkflowClientOptions( + WorkflowClientOptions.newBuilder() + .setInterceptors(new SimpleClientInterceptor(clientCounter)) + .build()) + .build(); + + @Test + public void testInterceptor() { + WorkflowClient workflowClient = testWorkflowRule.getWorkflowClient(); + + MyWorkflow workflow = + workflowClient.newWorkflowStub( + MyWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(WORKFLOW_ID) + .build()); + + WorkflowClient.start(workflow::exec); + + workflow.signalNameAndTitle("John", "Customer"); + + String name = workflow.queryName(); + String title = workflow.queryTitle(); + + workflow.exit(); + + // Wait for workflow completion via WorkflowStub + WorkflowStub untyped = WorkflowStub.fromTyped(workflow); + String result = untyped.getResult(String.class); + + assertNotNull(result); + + assertNotNull(name); + assertEquals("John", name); + assertNotNull(title); + assertEquals("Customer", title); + + assertEquals(1, clientCounter.getNumOfWorkflowExecutions(WORKFLOW_ID)); + assertEquals(1, clientCounter.getNumOfGetResults(WORKFLOW_ID)); + assertEquals(2, clientCounter.getNumOfSignals(WORKFLOW_ID)); + assertEquals(2, clientCounter.getNumOfQueries(WORKFLOW_ID)); + } +} diff --git a/src/test/java/io/temporal/samples/interceptor/CountInterceptorTest.java b/src/test/java/io/temporal/samples/interceptor/WorkerCountInterceptorTest.java similarity index 86% rename from src/test/java/io/temporal/samples/interceptor/CountInterceptorTest.java rename to src/test/java/io/temporal/samples/interceptor/WorkerCountInterceptorTest.java index 1ad4104e2..c242d8bd3 100644 --- a/src/test/java/io/temporal/samples/interceptor/CountInterceptorTest.java +++ b/src/test/java/io/temporal/samples/interceptor/WorkerCountInterceptorTest.java @@ -33,7 +33,7 @@ import org.junit.Rule; import org.junit.Test; -public class CountInterceptorTest { +public class WorkerCountInterceptorTest { private static final String WORKFLOW_ID = "TestInterceptorWorkflow"; private static final String CHILD_WORKFLOW_ID = "TestInterceptorChildWorkflow"; @@ -81,13 +81,13 @@ public void testInterceptor() { assertNotNull(title); assertEquals("Customer", title); - assertEquals(1, Counter.getNumOfWorkflowExecutions(WORKFLOW_ID)); - assertEquals(1, Counter.getNumOfChildWorkflowExecutions(WORKFLOW_ID)); + assertEquals(1, WorkerCounter.getNumOfWorkflowExecutions(WORKFLOW_ID)); + assertEquals(1, WorkerCounter.getNumOfChildWorkflowExecutions(WORKFLOW_ID)); // parent workflow does not execute any activities - assertEquals(0, Counter.getNumOfActivityExecutions(WORKFLOW_ID)); + assertEquals(0, WorkerCounter.getNumOfActivityExecutions(WORKFLOW_ID)); // child workflow executes 2 activities - assertEquals(2, Counter.getNumOfActivityExecutions(CHILD_WORKFLOW_ID)); - assertEquals(2, Counter.getNumOfSignals(WORKFLOW_ID)); - assertEquals(2, Counter.getNumOfQueries(WORKFLOW_ID)); + assertEquals(2, WorkerCounter.getNumOfActivityExecutions(CHILD_WORKFLOW_ID)); + assertEquals(2, WorkerCounter.getNumOfSignals(WORKFLOW_ID)); + assertEquals(2, WorkerCounter.getNumOfQueries(WORKFLOW_ID)); } } From f2f4f026d3d03b9b55428598f8531f5094f1346c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Sep 2022 10:12:41 -0400 Subject: [PATCH 017/240] Bump mockito-core from 4.7.0 to 4.8.0 (#355) Bumps [mockito-core](https://github.com/mockito/mockito) from 4.7.0 to 4.8.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.7.0...v4.8.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 73c569da3..5c2db5d0f 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:1.16.0") testImplementation "junit:junit:4.13.2" - testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.7.0' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.8.0' testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' testImplementation "org.junit.jupiter:junit-jupiter-api" From e6acab9e2cf08596522d2d60e0d0cbbaf97143f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Sep 2022 10:13:50 -0400 Subject: [PATCH 018/240] Bump opentelemetry-bom from 1.17.0 to 1.18.0 (#358) Bumps [opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.17.0 to 1.18.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.17.0...v1.18.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5c2db5d0f..110546fdf 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ repositories { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.4")) - implementation(platform("io.opentelemetry:opentelemetry-bom:1.17.0")) + implementation(platform("io.opentelemetry:opentelemetry-bom:1.18.0")) implementation(platform("org.junit:junit-bom:5.9.0")) implementation "io.temporal:temporal-sdk:1.16.0" From 270c7fdfe41c26c739d1dbf2cea03b3554219c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Fri, 30 Sep 2022 17:40:31 +0200 Subject: [PATCH 019/240] added replay-test (#360) * added replay-test * added licence to class header * removed harcoded event history in test --- .../hello/HelloActivityReplayTest.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java b/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java new file mode 100644 index 000000000..977d41708 --- /dev/null +++ b/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static org.hamcrest.MatcherAssert.assertThat; + +import io.temporal.activity.ActivityOptions; +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.internal.common.WorkflowExecutionHistory; +import io.temporal.testing.TestWorkflowRule; +import io.temporal.testing.WorkflowReplayer; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +/** + * Unit test for replay {@link HelloActivity.GreetingWorkflowImpl}. Doesn't use an external Temporal + * service. + */ +public class HelloActivityReplayTest { + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder().setDoNotStart(true).build(); + + @Test + public void replayWorkflowExecution() throws Exception { + + final String eventHistory = executeWorkflow(HelloActivity.GreetingWorkflowImpl.class); + + WorkflowReplayer.replayWorkflowExecution( + eventHistory, HelloActivity.GreetingWorkflowImpl.class); + } + + @Test + public void replayWorkflowExecutionNonDeterministic() { + + // We are executing the workflow with one implementation (GreetingWorkflowImplTest) and trying + // to replay the even history with a different implementation (GreetingWorkflowImpl), + // which causes an exception during the replay + + try { + + final String eventHistory = executeWorkflow(GreetingWorkflowImplTest.class); + + WorkflowReplayer.replayWorkflowExecution( + eventHistory, HelloActivity.GreetingWorkflowImpl.class); + + Assert.fail("Should have thrown an Exception"); + } catch (Exception e) { + assertThat( + e.getMessage(), + CoreMatchers.containsString("error=io.temporal.worker.NonDeterministicException")); + } + } + + private String executeWorkflow( + Class workflowImplementationType) { + + testWorkflowRule + .getWorker() + .registerActivitiesImplementations(new HelloActivity.GreetingActivitiesImpl()); + + testWorkflowRule.getWorker().registerWorkflowImplementationTypes(workflowImplementationType); + + testWorkflowRule.getTestEnvironment().start(); + + HelloActivity.GreetingWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloActivity.GreetingWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + WorkflowExecution execution = WorkflowStub.fromTyped(workflow).start("Hello"); + // wait until workflow completes + WorkflowStub.fromTyped(workflow).getResult(String.class); + + return new WorkflowExecutionHistory(testWorkflowRule.getHistory(execution)).toJson(true); + } + + public static class GreetingWorkflowImplTest implements HelloActivity.GreetingWorkflow { + + private final HelloActivity.GreetingActivities activities = + Workflow.newActivityStub( + HelloActivity.GreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String getGreeting(String name) { + Workflow.sleep(100); + return activities.composeGreeting("Hello", name); + } + } +} From 14896dd88548fd9352ec594d8215a874343d274e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Sep 2022 11:41:14 -0400 Subject: [PATCH 020/240] Bump junit-bom from 5.9.0 to 5.9.1 (#362) Bumps [junit-bom](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.1) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 110546fdf..c95880c7b 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ repositories { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.4")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.18.0")) - implementation(platform("org.junit:junit-bom:5.9.0")) + implementation(platform("org.junit:junit-bom:5.9.1")) implementation "io.temporal:temporal-sdk:1.16.0" implementation "io.temporal:temporal-opentracing:1.16.0" From dbbd07d7600e883f0e3f15789a41a48ebb649be5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 10:09:55 -0400 Subject: [PATCH 021/240] Bump opentelemetry-bom from 1.18.0 to 1.19.0 (#367) Bumps [opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.18.0 to 1.19.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.18.0...v1.19.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c95880c7b..8100994d8 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ repositories { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.4")) - implementation(platform("io.opentelemetry:opentelemetry-bom:1.18.0")) + implementation(platform("io.opentelemetry:opentelemetry-bom:1.19.0")) implementation(platform("org.junit:junit-bom:5.9.1")) implementation "io.temporal:temporal-sdk:1.16.0" From 1e7551b37016fd218dbb723f803540851126483b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 10:11:28 -0400 Subject: [PATCH 022/240] Bump net.ltgt.errorprone from 2.0.2 to 3.0.1 (#370) Bumps net.ltgt.errorprone from 2.0.2 to 3.0.1. --- updated-dependencies: - dependency-name: net.ltgt.errorprone dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8100994d8..a2e2d419d 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id 'com.github.sherter.google-java-format' version '0.9' - id "net.ltgt.errorprone" version "2.0.2" + id "net.ltgt.errorprone" version "3.0.1" } apply plugin: 'java' From 2a25bc291a9dc0b83b81cfcd2d1a5709d81de6bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 10:16:30 -0400 Subject: [PATCH 023/240] Bump jackson-bom from 2.13.4 to 2.13.4.20221013 (#372) Bumps [jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.13.4 to 2.13.4.20221013. - [Release notes](https://github.com/FasterXML/jackson-bom/releases) - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.13.4...jackson-bom-2.13.4.20221013) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a2e2d419d..1016c3d68 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ repositories { } dependencies { - implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.4")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.4.20221013")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.19.0")) implementation(platform("org.junit:junit-bom:5.9.1")) From e4efac7e9d1d8b75f93fdeb658f5f1cd98b71e0c Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Mon, 17 Oct 2022 13:36:10 -0400 Subject: [PATCH 024/240] fix use of deprecated api (#371) Signed-off-by: Tihomir Surdilovic Signed-off-by: Tihomir Surdilovic --- .../java/io/temporal/samples/hello/HelloSearchAttributes.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java b/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java index 2cb267747..1fcb72574 100644 --- a/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java +++ b/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java @@ -30,6 +30,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.common.converter.DataConverter; +import io.temporal.common.converter.GlobalDataConverter; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -243,7 +244,7 @@ private static String generateDateTimeFieldValue() { // example for extracting a value from search attributes private static String getKeywordFromSearchAttribute(SearchAttributes searchAttributes) { Payload field = searchAttributes.getIndexedFieldsOrThrow("CustomKeywordField"); - DataConverter dataConverter = DataConverter.getDefaultInstance(); + DataConverter dataConverter = GlobalDataConverter.get(); return dataConverter.fromPayload(field, String.class, String.class); } } From 181569afcc83760d15118e5a73d0dd2848dc3665 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Mon, 17 Oct 2022 13:41:59 -0400 Subject: [PATCH 025/240] adding codeowner (#375) Signed-off-by: Tihomir Surdilovic Signed-off-by: Tihomir Surdilovic --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 91cbd4ac8..a49757761 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # Primary owners -* @tsurdilo @Spikhalskiy \ No newline at end of file +* @tsurdilo @Spikhalskiy @antmendoza \ No newline at end of file From fd153a014f10349c7891347e4e30e98a07796e0a Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Mon, 17 Oct 2022 14:01:59 -0400 Subject: [PATCH 026/240] small fix to hello search attributes sample (#376) Signed-off-by: Tihomir Surdilovic Signed-off-by: Tihomir Surdilovic --- .../java/io/temporal/samples/hello/HelloSearchAttributes.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java b/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java index 1fcb72574..bd54549b6 100644 --- a/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java +++ b/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java @@ -93,7 +93,7 @@ public interface GreetingActivities { } // Define the workflow implementation which implements our getGreeting workflow method. - public static class GreetingWorkflowImpl implements HelloActivity.GreetingWorkflow { + public static class GreetingWorkflowImpl implements GreetingWorkflow { /** * Define the GreetingActivities stub. Activity stubs implement activity interfaces and proxy From e4850fb21fdee72c862e21918ad1abd6e8bdd012 Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Mon, 24 Oct 2022 14:12:56 -0400 Subject: [PATCH 027/240] Upgrade docker image to eclipse-temurin:8-focal (#378) --- docker/buildkite/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/buildkite/Dockerfile b/docker/buildkite/Dockerfile index 73240fdd1..f9d74f88d 100644 --- a/docker/buildkite/Dockerfile +++ b/docker/buildkite/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8-slim +FROM eclipse-temurin:8-focal # Git is needed in order to update the dls submodule RUN apt-get update && apt-get install -y wget protobuf-compiler git From 62533e2f0894d9a6da0a78c79416d36e6ed0b40d Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Tue, 25 Oct 2022 19:25:38 -0400 Subject: [PATCH 028/240] Java SDK v1.17.0 (#379) --- build.gradle | 20 ++++++++++++------- .../temporal/samples/asyncchild/Starter.java | 3 ++- .../samples/getresultsasync/Starter.java | 3 ++- .../samples/hello/HelloCancellationScope.java | 3 ++- .../listworkflows/CustomerActivitiesImpl.java | 3 ++- .../samples/listworkflows/Starter.java | 3 ++- .../samples/terminateworkflow/Starter.java | 3 ++- .../temporal/samples/tracing/TracingTest.java | 2 +- 8 files changed, 26 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 1016c3d68..ea547c88c 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ apply plugin: 'java' apply plugin: 'com.github.sherter.google-java-format' googleJavaFormat { - toolVersion '1.7' + toolVersion (JavaVersion.current().isJava11Compatible() ? '1.15.0' : '1.7') } java { @@ -30,8 +30,8 @@ dependencies { implementation(platform("io.opentelemetry:opentelemetry-bom:1.19.0")) implementation(platform("org.junit:junit-bom:5.9.1")) - implementation "io.temporal:temporal-sdk:1.16.0" - implementation "io.temporal:temporal-opentracing:1.16.0" + implementation "io.temporal:temporal-sdk:1.17.0" + implementation "io.temporal:temporal-opentracing:1.17.0" implementation "com.fasterxml.jackson.core:jackson-databind" implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' @@ -59,18 +59,24 @@ dependencies { // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' - testImplementation("io.temporal:temporal-testing:1.16.0") + testImplementation("io.temporal:temporal-testing:1.17.0") testImplementation "junit:junit:4.13.2" - testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.8.0' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.8.1' testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' testImplementation "org.junit.jupiter:junit-jupiter-api" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" testRuntimeOnly "org.junit.vintage:junit-vintage-engine" - errorproneJavac("com.google.errorprone:javac:9+181-r4173-1") - errorprone("com.google.errorprone:error_prone_core:2.10.0") + dependencies { + errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') + if (JavaVersion.current().isJava11Compatible()) { + errorprone('com.google.errorprone:error_prone_core:2.16') + } else { + errorprone('com.google.errorprone:error_prone_core:2.10.0') + } + } } compileJava { diff --git a/src/main/java/io/temporal/samples/asyncchild/Starter.java b/src/main/java/io/temporal/samples/asyncchild/Starter.java index 21e6d0771..126918043 100644 --- a/src/main/java/io/temporal/samples/asyncchild/Starter.java +++ b/src/main/java/io/temporal/samples/asyncchild/Starter.java @@ -28,6 +28,7 @@ import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.util.concurrent.TimeUnit; public class Starter { @@ -85,7 +86,7 @@ private static String getStatusAsString(WorkflowExecution execution) { private static void sleep(int seconds) { try { - Thread.sleep(seconds * 1000); + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); System.exit(0); diff --git a/src/main/java/io/temporal/samples/getresultsasync/Starter.java b/src/main/java/io/temporal/samples/getresultsasync/Starter.java index e6812f9ae..573cc7e90 100644 --- a/src/main/java/io/temporal/samples/getresultsasync/Starter.java +++ b/src/main/java/io/temporal/samples/getresultsasync/Starter.java @@ -22,6 +22,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import java.util.concurrent.TimeUnit; public class Starter { @@ -74,7 +75,7 @@ public static void main(String[] args) { private static void sleep(int seconds) { try { - Thread.sleep(seconds * 1000); + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); } catch (InterruptedException e) { System.out.println("Exception: " + e.getMessage()); System.exit(0); diff --git a/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java b/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java index 0dbf5f1ae..d7b31ce88 100644 --- a/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java +++ b/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java @@ -43,6 +43,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; +import java.util.concurrent.TimeUnit; /** * Sample Temporal Workflow Definition that demonstrates parallel Activity Executions with a @@ -236,7 +237,7 @@ public String composeGreeting(String greeting, String name) { private void sleep(int seconds) { try { - Thread.sleep(seconds * 1000); + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); } catch (InterruptedException ee) { // Empty } diff --git a/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java b/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java index f6fd52ac4..f7151c4b1 100644 --- a/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java +++ b/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java @@ -19,6 +19,7 @@ package io.temporal.samples.listworkflows; +import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,7 +47,7 @@ public void sendUpdateEmail(Customer customer) { private void sleepSeconds(int seconds) { try { - Thread.sleep(seconds * 1000); + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); } catch (InterruptedException e) { // This is being swallowed on purpose Thread.currentThread().interrupt(); diff --git a/src/main/java/io/temporal/samples/listworkflows/Starter.java b/src/main/java/io/temporal/samples/listworkflows/Starter.java index bb426f010..d03039a7a 100644 --- a/src/main/java/io/temporal/samples/listworkflows/Starter.java +++ b/src/main/java/io/temporal/samples/listworkflows/Starter.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; public class Starter { public static final String TASK_QUEUE = "customerTaskQueue"; @@ -153,7 +154,7 @@ private static void stopWorkflows(List customers) { private static void sleep(int seconds) { try { - Thread.sleep(seconds * 1000); + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); } catch (InterruptedException e) { System.out.println("Exception: " + e.getMessage()); System.exit(0); diff --git a/src/main/java/io/temporal/samples/terminateworkflow/Starter.java b/src/main/java/io/temporal/samples/terminateworkflow/Starter.java index 58b03e062..3b9d17fed 100644 --- a/src/main/java/io/temporal/samples/terminateworkflow/Starter.java +++ b/src/main/java/io/temporal/samples/terminateworkflow/Starter.java @@ -29,6 +29,7 @@ import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.util.concurrent.TimeUnit; public class Starter { @@ -82,7 +83,7 @@ private static void createWorker() { */ private static void sleepSeconds(int seconds) { try { - Thread.sleep(seconds * 1000); + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); System.exit(0); diff --git a/src/test/java/io/temporal/samples/tracing/TracingTest.java b/src/test/java/io/temporal/samples/tracing/TracingTest.java index 370f25ada..ef95cb3e4 100644 --- a/src/test/java/io/temporal/samples/tracing/TracingTest.java +++ b/src/test/java/io/temporal/samples/tracing/TracingTest.java @@ -48,7 +48,7 @@ public class TracingTest { private final InMemoryReporter reporter = new InMemoryReporter(); - private final Sampler sampler = new ConstSampler(true);; + private final Sampler sampler = new ConstSampler(true); private final Tracer tracer = new JaegerTracer.Builder("temporal-test").withReporter(reporter).withSampler(sampler).build(); From 38784154a8c106ae17b99f7a068fb385bc76d308 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Oct 2022 19:26:30 -0400 Subject: [PATCH 029/240] Bump mockito-core from 4.8.0 to 4.8.1 (#377) Bumps [mockito-core](https://github.com/mockito/mockito) from 4.8.0 to 4.8.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.8.0...v4.8.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 076f8e47660dbdfd8dce5887b016bf9cc0dbdc00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Nov 2022 21:16:08 -0500 Subject: [PATCH 030/240] Bump jackson-bom from 2.13.4.20221013 to 2.14.0 (#381) Bumps [jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.13.4.20221013 to 2.14.0. - [Release notes](https://github.com/FasterXML/jackson-bom/releases) - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.13.4.20221013...jackson-bom-2.14.0) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ea547c88c..b976c09d0 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ repositories { } dependencies { - implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.4.20221013")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.0")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.19.0")) implementation(platform("org.junit:junit-bom:5.9.1")) From 8f3b5c674b25c5ae5dfef0b5ecec33f180f81c6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Nov 2022 21:22:31 -0500 Subject: [PATCH 031/240] Bump opentelemetry-bom from 1.19.0 to 1.20.1 (#386) Bumps [opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.19.0 to 1.20.1. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.19.0...v1.20.1) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b976c09d0..4097d426b 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ repositories { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.0")) - implementation(platform("io.opentelemetry:opentelemetry-bom:1.19.0")) + implementation(platform("io.opentelemetry:opentelemetry-bom:1.20.1")) implementation(platform("org.junit:junit-bom:5.9.1")) implementation "io.temporal:temporal-sdk:1.17.0" From 2d8a3927ba7ba6db64b4d1a815ff57a44227eb4b Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Sat, 26 Nov 2022 18:47:20 -0800 Subject: [PATCH 032/240] Batch workflow samples: Iterator and SlidingWindow (#387) * Added batch iterator workflow implementation * Added slideingwindow * Added partitioning to sliding window * Fixed directory name * Added missing WorkflowMethod annotation * Fully functioning slidingwindow * Fixed SlidingWindowBatchWorkflowTest * Added IteratorBatchWorkflowTest * Added README and renaming * Restored TransferWorkflowTest * Self code review * Renamed IteratorBatchWorkflowWorker to IteratorBatchWorker --- README.md | 4 + .../batch/iterator/IteratorBatchStarter.java | 46 ++++++ .../batch/iterator/IteratorBatchWorker.java | 49 ++++++ .../batch/iterator/IteratorBatchWorkflow.java | 37 +++++ .../iterator/IteratorBatchWorkflowImpl.java | 82 ++++++++++ .../temporal/samples/batch/iterator/README.md | 24 +++ .../samples/batch/iterator/Record.java | 41 +++++ .../samples/batch/iterator/RecordLoader.java | 43 ++++++ .../batch/iterator/RecordLoaderImpl.java | 42 ++++++ .../iterator/RecordProcessorWorkflow.java | 32 ++++ .../iterator/RecordProcessorWorkflowImpl.java | 38 +++++ .../batch/slidingwindow/BatchProgress.java | 45 ++++++ .../batch/slidingwindow/BatchWorkflow.java | 42 ++++++ .../slidingwindow/BatchWorkflowImpl.java | 72 +++++++++ .../slidingwindow/ProcessBatchInput.java | 97 ++++++++++++ .../samples/batch/slidingwindow/README.md | 32 ++++ .../samples/batch/slidingwindow/Record.java | 41 +++++ .../batch/slidingwindow/RecordIterable.java | 112 ++++++++++++++ .../batch/slidingwindow/RecordLoader.java | 44 ++++++ .../batch/slidingwindow/RecordLoaderImpl.java | 45 ++++++ .../RecordProcessorWorkflow.java | 35 +++++ .../RecordProcessorWorkflowImpl.java | 54 +++++++ .../SlidingWindowBatchStarter.java | 40 +++++ .../SlidingWindowBatchWorker.java | 49 ++++++ .../SlidingWindowBatchWorkflow.java | 43 ++++++ .../SlidingWindowBatchWorkflowImpl.java | 142 ++++++++++++++++++ .../IteratorIteratorBatchWorkflowTest.java | 61 ++++++++ .../SlidingWindowBatchWorkflowTest.java | 73 +++++++++ 28 files changed, 1465 insertions(+) create mode 100644 src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java create mode 100644 src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java create mode 100644 src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java create mode 100644 src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/iterator/README.md create mode 100644 src/main/java/io/temporal/samples/batch/iterator/Record.java create mode 100644 src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java create mode 100644 src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java create mode 100644 src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/README.md create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/Record.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java create mode 100644 src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java create mode 100644 src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java create mode 100644 src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java diff --git a/README.md b/README.md index 420aefecf..f17c52432 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,10 @@ All tests are available under [src/test/java](https://github.com/temporalio/samp - [**Polling Services**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion +- [**Iterator Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/batch/iterator): Batch job implementation using the workflow iterator pattern. + +- [**Sliding Window Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. + ### API demonstrations - [**Updatable Timer**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java new file mode 100644 index 000000000..8e9530c36 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import static io.temporal.samples.batch.iterator.IteratorBatchWorker.TASK_QUEUE; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; + +/** Starts a single execution of IteratorBatchWorkflow. */ +public class IteratorBatchStarter { + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient workflowClient = WorkflowClient.newInstance(service); + WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build(); + IteratorBatchWorkflow batchWorkflow = + workflowClient.newWorkflowStub(IteratorBatchWorkflow.class, options); + WorkflowExecution execution = WorkflowClient.start(batchWorkflow::processBatch, 5, 0); + System.out.println( + "Started batch workflow. WorkflowId=" + + execution.getWorkflowId() + + ", RunId=" + + execution.getRunId()); + System.exit(0); + } +} diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java new file mode 100644 index 000000000..ecb9edf38 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +/** + * A worker process that hosts implementations of IteratorBatchWorkflow and RecordProcessorWorkflow + * as well as RecordLoader activity. + */ +public final class IteratorBatchWorker { + + static final String TASK_QUEUE = "IteratorBatch"; + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(TASK_QUEUE); + + worker.registerWorkflowImplementationTypes( + IteratorBatchWorkflowImpl.class, RecordProcessorWorkflowImpl.class); + + worker.registerActivitiesImplementations(new RecordLoaderImpl()); + factory.start(); + System.out.println("Worker started for task queue: " + TASK_QUEUE); + } +} diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java new file mode 100644 index 000000000..c5d55de3a --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface IteratorBatchWorkflow { + + /** + * Processes the batch of records. + * + * @param offset the offset of the first record to process. 0 to start the batch processing. + * @param pageSize the number of records to process in a single workflow run. + * @return total number of processed records. + */ + @WorkflowMethod + int processBatch(int pageSize, int offset); +} diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java new file mode 100644 index 000000000..4c46cb268 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Async; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +/** + * Implements iterator workflow pattern. + * + *

A single workflow run processes a single page of records in parallel. Each record is processed + * using its own RecordProcessorWorkflow child workflow. + * + *

After all child workflows complete the new run of the parent workflow is created using + * continue as new. The new run processes the next page of records. This way practically unlimited + * set of records can be processed. + */ +public final class IteratorBatchWorkflowImpl implements IteratorBatchWorkflow { + + private final RecordLoader recordLoader = + Workflow.newActivityStub( + RecordLoader.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(5)).build()); + + /** Stub used to continue-as-new. */ + private final IteratorBatchWorkflow nextRun = + Workflow.newContinueAsNewStub(IteratorBatchWorkflow.class); + + @Override + public int processBatch(int pageSize, int offset) { + // Loads a page of records + List records = recordLoader.getRecords(pageSize, offset); + // Starts a child per record asynchrnously. + List> results = new ArrayList<>(records.size()); + for (Record record : records) { + // Uses human friendly child id. + String childId = Workflow.getInfo().getWorkflowId() + "/" + record.getId(); + RecordProcessorWorkflow processor = + Workflow.newChildWorkflowStub( + RecordProcessorWorkflow.class, + ChildWorkflowOptions.newBuilder().setWorkflowId(childId).build()); + Promise result = Async.procedure(processor::processRecord, record); + results.add(result); + } + // Waits for all children to complete. + Promise.allOf(results).get(); + + // Skips error handling for the sample brevity. + // So failed RecordProcessorWorkflows are ignored. + + // No more records in the dataset. Completes the workflow. + if (records.isEmpty()) { + return offset; + } + + // Continues as new with the increased offset. + return nextRun.processBatch(pageSize, offset + records.size()); + } +} diff --git a/src/main/java/io/temporal/samples/batch/iterator/README.md b/src/main/java/io/temporal/samples/batch/iterator/README.md new file mode 100644 index 000000000..bde0cccb5 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/README.md @@ -0,0 +1,24 @@ +A sample implementation of the workflow iterator pattern. + +A workflow starts a configured number of child workflows in parallel. Each child processes a single record. After all +children complete the parent calls continue-as-new and starts the children for the next page of records. This allows +processing a set of records of any size. The advantage of this approach is simplicity. The main disadvantage is that it +processes records in batches, with each batch waiting for the slowest child workflow. + +A variation of this pattern runs activities instead of child workflows. + +#### Running the Iterator Batch Sample + +The sample has two executables. Execute each command in a separate terminal window. + +The first command runs the Worker that hosts the Workflow and Activity Executions. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.batch.iterator.IteratorBatchWorker +``` + +The second command start the Workflow Execution. Each time the command runs, it starts a new Workflow Execution. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.batch.iterator.IteratorBatchStarter +``` diff --git a/src/main/java/io/temporal/samples/batch/iterator/Record.java b/src/main/java/io/temporal/samples/batch/iterator/Record.java new file mode 100644 index 000000000..ef1698277 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/Record.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +/** Record to process. A real application would add a use case specific data. */ +public class Record { + private int id; + + public Record(int id) { + this.id = id; + } + + /** JSON deserializer needs it */ + public Record() {} + + public int getId() { + return id; + } + + @Override + public String toString() { + return "Record{" + "id=" + id + '}'; + } +} diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java b/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java new file mode 100644 index 000000000..77da1e592 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import io.temporal.activity.ActivityInterface; +import java.util.List; + +/** + * Activity that is used to iterate over a list of records. + * + *

A specific implementation depends on a use case. For example, it can execute an SQL DB query + * or read a comma delimited file. More complex use cases would need passing a different type of + * offset parameter. + */ +@ActivityInterface +public interface RecordLoader { + + /** + * Returns the next page of records. + * + * @param offset offset of the next page. + * @param pageSize maximum number of records to return. + * @return empty list if no more records to process. + */ + List getRecords(int pageSize, int offset); +} diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java b/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java new file mode 100644 index 000000000..389c78967 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import java.util.ArrayList; +import java.util.List; + +/** Fake implementation of RecordLoader. */ +public final class RecordLoaderImpl implements RecordLoader { + + // The sample always returns 5 pages. + // The real application would iterate over an existing dataset or file. + public static final int PAGE_COUNT = 5; + + @Override + public List getRecords(int pageSize, int offset) { + List records = new ArrayList<>(pageSize); + if (offset < pageSize * PAGE_COUNT) { + for (int i = 0; i < pageSize; i++) { + records.add(new Record(offset + i)); + } + } + return records; + } +} diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java b/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java new file mode 100644 index 000000000..01df5689e --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +/** Workflow that implements processing of a single record. */ +@WorkflowInterface +public interface RecordProcessorWorkflow { + + /** Processes a single record */ + @WorkflowMethod + void processRecord(Record r); +} diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java new file mode 100644 index 000000000..d2e22f2af --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.Random; +import org.slf4j.Logger; + +/** Fake RecordProcessorWorkflow implementation. */ +public class RecordProcessorWorkflowImpl implements RecordProcessorWorkflow { + public static final Logger log = Workflow.getLogger(RecordProcessorWorkflowImpl.class); + private final Random random = Workflow.newRandom(); + + @Override + public void processRecord(Record r) { + // Simulate some processing + Workflow.sleep(Duration.ofSeconds(random.nextInt(30))); + log.info("Processed " + r); + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java b/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java new file mode 100644 index 000000000..a09b56479 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import java.util.Set; + +/** Used as a result of {@link SlidingWindowBatchWorkflow#getProgress()} query. */ +public final class BatchProgress { + + private final int progress; + + private final Set currentRecords; + + public BatchProgress(int progress, Set currentRecords) { + this.progress = progress; + this.currentRecords = currentRecords; + } + + /** Count of completed record processing child workflows. */ + public int getProgress() { + return progress; + } + + /** Ids of records that are currently being processed by child workflows. */ + public Set getCurrentRecords() { + return currentRecords; + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java b/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java new file mode 100644 index 000000000..40eb14c7b --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface BatchWorkflow { + + /** + * Processes a batch of records using multiple parallel sliding window workflows. + * + * @param pageSize the number of records to start processing in a single sliding window workflow + * run. + * @param slidingWindowSize the number of records to process in parallel by a single sliding + * window workflow. Can be larger than the pageSize. + * @param partitions defines the number of SlidingWindowBatchWorkflows to run in parallel. If + * number of partitions is too low the update rate of a single SlidingWindowBatchWorkflows can + * get too high. + * @return total number of processed records. + */ + @WorkflowMethod + int processBatch(int pageSize, int slidingWindowSize, int partitions); +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java new file mode 100644 index 000000000..2e96dc8ba --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Async; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +/** Implements BatchWorkflow by running multiple SlidingWindowBatchWorkflows in parallel. */ +public class BatchWorkflowImpl implements BatchWorkflow { + + private final RecordLoader recordLoader = + Workflow.newActivityStub( + RecordLoader.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(5)).build()); + + @Override + public int processBatch(int pageSize, int slidingWindowSize, int partitions) { + // The sample partitions the data set into continuous ranges. + // A real application can choose any other way to divide the records into multiple collections. + int totalCount = recordLoader.getRecordCount(); + int partitionSize = totalCount / partitions + (totalCount % partitions > 0 ? 1 : 0); + List> results = new ArrayList<>(partitions); + for (int i = 0; i < partitions; i++) { + // Makes child id more user-friendly + String childId = Workflow.getInfo().getWorkflowId() + "/" + i; + SlidingWindowBatchWorkflow partitionWorkflow = + Workflow.newChildWorkflowStub( + SlidingWindowBatchWorkflow.class, + ChildWorkflowOptions.newBuilder().setWorkflowId(childId).build()); + // Define partition boundaries. + int offset = partitionSize * i; + int maximumOffset = Math.min(offset + partitionSize, totalCount); + + ProcessBatchInput input = new ProcessBatchInput(); + input.setPageSize(pageSize); + input.setSlidingWindowSize(slidingWindowSize); + input.setOffset(offset); + input.setMaximumOffset(maximumOffset); + + Promise partitionResult = Async.function(partitionWorkflow::processBatch, input); + results.add(partitionResult); + } + int result = 0; + for (Promise partitionResult : results) { + result += partitionResult.get(); + } + return result; + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java b/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java new file mode 100644 index 000000000..4f4013e56 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import java.util.HashSet; +import java.util.Set; + +/** Input of {@link SlidingWindowBatchWorkflow#processBatch(ProcessBatchInput)} */ +public final class ProcessBatchInput { + private int pageSize; + private int slidingWindowSize; + + int offset; + + private int maximumOffset; + + private int progress; + + private Set currentRecords = new HashSet<>(); + + /** the number of records to load in a single RecordLoader.getRecords call. */ + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + /** the number of parallel record processing child workflows to execute. */ + public void setSlidingWindowSize(int slidingWindowSize) { + this.slidingWindowSize = slidingWindowSize; + } + + /** index of the first record to process. 0 to start the batch processing. */ + public void setOffset(int offset) { + this.offset = offset; + } + + /** The maximum offset (exclusive) to process by this workflow. */ + public void setMaximumOffset(int maximumOffset) { + this.maximumOffset = maximumOffset; + } + + /** Total number of records processed so far by this workflow. */ + public void setProgress(int progress) { + this.progress = progress; + } + + /** + * Ids of records that are being processed by child workflows. + * + *

This puts a limit on the sliding window size as workflow arguments cannot exceed 2MB in JSON + * format. Another practical limit is the number of signals a workflow can handle per second. + * Adjust the number of partitions to keep this rate at a reasonable value. + */ + public void setCurrentRecords(Set currentRecords) { + this.currentRecords = currentRecords; + } + + public int getPageSize() { + return pageSize; + } + + public int getSlidingWindowSize() { + return slidingWindowSize; + } + + public int getOffset() { + return offset; + } + + public int getMaximumOffset() { + return maximumOffset; + } + + public int getProgress() { + return progress; + } + + public Set getCurrentRecords() { + return currentRecords; + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/README.md b/src/main/java/io/temporal/samples/batch/slidingwindow/README.md new file mode 100644 index 000000000..d32aef7b4 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/README.md @@ -0,0 +1,32 @@ +A sample implementation of a batch processing workflow that maintains a sliding window of record processing workflows. + +A workflow starts a configured number of child workflows in parallel. Each child processes a single record. When a child +completes a new child immediately started. A parent workflow calls continue-as-new after starting a preconfigured number +of children. A child completion is reported through a signal as a parent cannot directly wait for a child started by a +previous run. + +Multiple instances of SlidingWindowBatchWorkflow run in parallel each processing a subset of records to support higher +total rate of processing. + +#### Running the Sliding Window Batch Sample + +The sample has two executables. Execute each command in a separate terminal window. + +The first command runs the Worker that hosts the Workflow and Activity Executions. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.batch.hslidingwindow.SlidingWindowBatchWorkflowWorker +``` + +Note that `Caused by: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: UnhandledCommand` info messages in the output +are expected and benign. They ensure that signals are not lost when there is a race condition between workflow calling +continue-as-new and receiving a signal. If these messages appear too frequently consider increasing the number of +partitions parameter passed to `BatchWorkflow.processBatch`. They will completely disappear +when [Issue1289](https://github.com/temporalio/temporal/issues/1289) is implemented. + +The second command start the BatchWorkflow Execution. Each time the command runs, it starts a new BatchWorkflow +Execution. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.batch.slidingwindow.SlidingWindowBatchStarter +``` diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/Record.java b/src/main/java/io/temporal/samples/batch/slidingwindow/Record.java new file mode 100644 index 000000000..3938fc098 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/Record.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +/** Record to process. */ +public class Record { + private int id; + + public Record(int id) { + this.id = id; + } + + /** Needed for JSON deserialization. */ + public Record() {} + + public int getId() { + return id; + } + + @Override + public String toString() { + return "Record{" + "id=" + id + '}'; + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java new file mode 100644 index 000000000..13cf644f6 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import org.jetbrains.annotations.NotNull; + +/** Iterable implementation that relies on RecordLoader activity. */ +public class RecordIterable implements Iterable { + + /** + * Iterator implementation that relies on RecordLoader activity. + * + *

This code assumes that RecordLoader.getRecords never returns a failure to the workflow. The + * real production application might make a different design choice. + */ + private class RecordIterator implements Iterator { + + /** + * The last page of records loaded through RecordLoader activity. The activity returns an empty + * page to indicate the end of iteration. + */ + private List lastPage; + + /** The offset of the last loaded batch of records. */ + private int offset; + + /** Index into the last loaded page of the next record to return. */ + private int index; + + RecordIterator() { + this.offset = initialOffset; + if (initialOffset > maximumOffset) { + this.lastPage = new ArrayList<>(); + } else { + int size = Math.min(pageSize, maximumOffset - offset); + this.lastPage = recordLoader.getRecords(size, offset); + } + } + + @Override + public boolean hasNext() { + return !lastPage.isEmpty(); + } + + @Override + public Record next() { + int size = lastPage.size(); + if (size == 0) { + throw new NoSuchElementException(); + } + Record result = lastPage.get(index++); + if (size == index) { + offset += index; + index = 0; + lastPage = recordLoader.getRecords(pageSize, offset); + } + return result; + } + } + + private final int initialOffset; + + private final int pageSize; + + private final int maximumOffset; + + private final RecordLoader recordLoader = + Workflow.newActivityStub( + RecordLoader.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(5)).build()); + + /** + * @param pageSize size of a single page to load. + * @param initialOffset the initial offset to load records from. + * @param maximumOffset the maximum offset (exclusive). + */ + public RecordIterable(int pageSize, int initialOffset, int maximumOffset) { + this.pageSize = pageSize; + this.initialOffset = initialOffset; + this.maximumOffset = maximumOffset; + } + + @NotNull + @Override + public Iterator iterator() { + return new RecordIterator(); + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java new file mode 100644 index 000000000..2969e8d06 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.activity.ActivityInterface; +import java.util.List; + +@ActivityInterface +public interface RecordLoader { + + /** + * Returns the next page of records. + * + * @param offset offset of the next page. + * @param pageSize maximum number of records to return. + * @return empty list if no more records to process. + */ + List getRecords(int pageSize, int offset); + + /** + * Returns the total record count. + * + *

Used to divide record ranges among partitions. Some applications might choose a completely + * different approach for partitioning the data set. + */ + int getRecordCount(); +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java new file mode 100644 index 000000000..0e86ca357 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import java.util.ArrayList; +import java.util.List; + +/** Fake loader implementation. The real application would iterate over a dataset or file. */ +public final class RecordLoaderImpl implements RecordLoader { + + private static final int TOTAL_COUNT = 300; + + @Override + public List getRecords(int pageSize, int offset) { + List records = new ArrayList<>(pageSize); + if (offset < TOTAL_COUNT) { + for (int i = offset; i < Math.min(offset + pageSize, TOTAL_COUNT); i++) { + records.add(new Record(i)); + } + } + return records; + } + + @Override + public int getRecordCount() { + return TOTAL_COUNT; + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java new file mode 100644 index 000000000..3a99115c0 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +/** Workflow that implements processing of a single record. */ +@WorkflowInterface +public interface RecordProcessorWorkflow { + + /** + * Processes a single record. Must report completion to a parent through {@link + * SlidingWindowBatchWorkflow#reportCompletion(int)} + */ + @WorkflowMethod + void processRecord(Record r); +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java new file mode 100644 index 000000000..995a6e0cd --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.Optional; +import java.util.Random; +import org.slf4j.Logger; + +/** Fake RecordProcessorWorkflow implementation. */ +public final class RecordProcessorWorkflowImpl implements RecordProcessorWorkflow { + public static final Logger log = Workflow.getLogger(RecordProcessorWorkflowImpl.class); + private final Random random = Workflow.newRandom(); + + @Override + public void processRecord(Record r) { + processRecordImpl(r); + // This workflow is always expected to have a parent. + // But for unit testing it might be useful to skip the notification. + Optional parentWorkflowId = Workflow.getInfo().getParentWorkflowId(); + if (parentWorkflowId.isPresent()) { + String parentId = parentWorkflowId.get(); + SlidingWindowBatchWorkflow parent = + Workflow.newExternalWorkflowStub(SlidingWindowBatchWorkflow.class, parentId); + // Notify parent about record processing completion + parent.reportCompletion(r.getId()); + } + } + + /** Application specific record processing logic goes here. */ + private void processRecordImpl(Record r) { + // Simulate some processing + Workflow.sleep(Duration.ofSeconds(random.nextInt(10))); + log.info("Processed " + r); + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java new file mode 100644 index 000000000..8c3329c37 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import static io.temporal.samples.batch.slidingwindow.SlidingWindowBatchWorker.TASK_QUEUE; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; + +public class SlidingWindowBatchStarter { + + @SuppressWarnings("CatchAndPrintStackTrace") + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient workflowClient = WorkflowClient.newInstance(service); + WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build(); + BatchWorkflow batchWorkflow = workflowClient.newWorkflowStub(BatchWorkflow.class, options); + WorkflowClient.start(batchWorkflow::processBatch, 10, 25, 3); + System.out.println("Started batch workflow with 3 partitions"); + System.exit(0); + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java new file mode 100644 index 000000000..2b1b6c1c4 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +/** Hosts sliding window batch sample workflow and activity implementations. */ +public final class SlidingWindowBatchWorker { + + static final String TASK_QUEUE = "SlidingWindow"; + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(TASK_QUEUE); + + worker.registerWorkflowImplementationTypes( + BatchWorkflowImpl.class, + SlidingWindowBatchWorkflowImpl.class, + RecordProcessorWorkflowImpl.class); + worker.registerActivitiesImplementations(new RecordLoaderImpl()); + + factory.start(); + + System.out.println("Worker started for task queue: " + TASK_QUEUE); + } +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java new file mode 100644 index 000000000..3a49126d6 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.workflow.QueryMethod; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface SlidingWindowBatchWorkflow { + + /** + * Process the batch of records. + * + * @return total number of processed records. + */ + @WorkflowMethod + int processBatch(ProcessBatchInput input); + + @SignalMethod + void reportCompletion(int recordId); + + @QueryMethod + BatchProgress getProgress(); +} diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java new file mode 100644 index 000000000..821308aaf --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.ParentClosePolicy; +import io.temporal.workflow.*; +import java.util.*; + +/** + * Implements batch processing by executing a specified number of workflows in parallel. A new + * record processing workflow is started when a previously started one completes. The child + * completion is reported through reportCompletion signal as it is not yet possible to passively + * wait for a workflow that was started by a previous run. + * + *

Calls continue-as-new after starting 100 children. Note that the sliding window size can be + * larger than 100. + */ +public final class SlidingWindowBatchWorkflowImpl implements SlidingWindowBatchWorkflow { + + /** Stub used to call continue-as-new. */ + private final SlidingWindowBatchWorkflow nextRun = + Workflow.newContinueAsNewStub(SlidingWindowBatchWorkflow.class); + + /** Contains ids of records that are being processed by child workflows. */ + private Set currentRecords; + + /** + * Used to accumulate records to remove for signals delivered before processBatch method started + * execution + */ + private Set recordsToRemove = new HashSet<>(); + + /** Count of completed record processing child workflows. */ + private int progress; + + /** @return number of processed records */ + @Override + public int processBatch(ProcessBatchInput input) { + WorkflowInfo info = Workflow.getInfo(); + this.progress = input.getProgress(); + this.currentRecords = input.getCurrentRecords(); + // Remove records for signals delivered before the workflow run started. + int countBefore = this.currentRecords.size(); + this.currentRecords.removeAll(recordsToRemove); + this.progress += countBefore - this.currentRecords.size(); + + int pageSize = input.getPageSize(); + int offset = input.getOffset(); + int maximumOffset = input.getMaximumOffset(); + int slidingWindowSize = input.getSlidingWindowSize(); + + Iterable records = new RecordIterable(pageSize, offset, maximumOffset); + List> childrenStartedByThisRun = new ArrayList<>(); + + Iterator recordIterator = records.iterator(); + while (true) { + // After starting slidingWindowSize children blocks until a completion signal is received. + Workflow.await(() -> currentRecords.size() < slidingWindowSize); + // Completes workflow, if no more records to process. + if (!recordIterator.hasNext()) { + // Awaits for all children to complete + Workflow.await(() -> currentRecords.size() == 0); + return offset + childrenStartedByThisRun.size(); + } + Record record = recordIterator.next(); + + // Uses ParentClosePolicy ABANDON to ensure that children survive continue-as-new of a parent. + // Assigns user-friendly child workflow id. + ChildWorkflowOptions childWorkflowOptions = + ChildWorkflowOptions.newBuilder() + .setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON) + .setWorkflowId(info.getWorkflowId() + "/" + record.getId()) + .build(); + + RecordProcessorWorkflow processor = + Workflow.newChildWorkflowStub(RecordProcessorWorkflow.class, childWorkflowOptions); + // Starts a child workflow asynchronously ignoring its result. + // The assumption is that the parent workflow doesn't need to deal with child workflow + // results and failures. Another assumption is that a child in any situation calls + // the reportCompletion signal. + Async.procedure(processor::processRecord, record); + // Resolves when a child reported successful start. + // Used to wait for a child start on continue-as-new. + Promise childStartedPromise = Workflow.getWorkflowExecution(processor); + childrenStartedByThisRun.add(childStartedPromise); + currentRecords.add(record.getId()); + // Continues-as-new after starting pageSize children + if (childrenStartedByThisRun.size() == pageSize) { + // Waits for all children to start. Without this wait, workflow completion through + // continue-as-new might lead to a situation when they never start. + // Assumes that they never fail to start as their automatically generated + // IDs are not expected to collide. + Promise.allOf(childrenStartedByThisRun).get(); + // Continues as new to keep the history size bounded + ProcessBatchInput newInput = new ProcessBatchInput(); + newInput.setPageSize(pageSize); + newInput.setSlidingWindowSize(slidingWindowSize); + newInput.setOffset(offset + childrenStartedByThisRun.size()); + newInput.setMaximumOffset(maximumOffset); + newInput.setProgress(progress); + newInput.setCurrentRecords(currentRecords); + return nextRun.processBatch(newInput); + } + } + } + + @Override + public void reportCompletion(int recordId) { + // Handle situation when signal handler is called before the workflow main method. + if (currentRecords == null) { + recordsToRemove.add(recordId); + return; + } + // Dedupes signals as in some edge cases they can be duplicated. + if (currentRecords.remove(recordId)) { + progress++; + } + } + + @Override + public BatchProgress getProgress() { + return new BatchProgress(progress, currentRecords); + } +} diff --git a/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java b/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java new file mode 100644 index 000000000..9a4346437 --- /dev/null +++ b/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.iterator; + +import static io.temporal.samples.batch.iterator.RecordLoaderImpl.PAGE_COUNT; +import static org.junit.Assert.assertTrue; + +import io.temporal.testing.TestWorkflowRule; +import io.temporal.workflow.Workflow; +import org.junit.Rule; +import org.junit.Test; + +public class IteratorIteratorBatchWorkflowTest { + + private static final int PAGE_SIZE = 10; + /** The sample RecordLoaderImpl always returns the fixed number pages. */ + private static boolean[] processedRecords = new boolean[PAGE_SIZE * PAGE_COUNT]; + + public static class TestRecordProcessorWorkflowImpl implements RecordProcessorWorkflow { + + @Override + public void processRecord(Record r) { + Workflow.sleep(5000); + processedRecords[r.getId()] = true; + } + } + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(IteratorBatchWorkflowImpl.class, TestRecordProcessorWorkflowImpl.class) + .setActivityImplementations(new RecordLoaderImpl()) + .build(); + + @Test + public void testBatchWorkflow() { + IteratorBatchWorkflow workflow = testWorkflowRule.newWorkflowStub(IteratorBatchWorkflow.class); + workflow.processBatch(3, 0); + + for (int i = 0; i < PAGE_SIZE; i++) { + assertTrue(processedRecords[i]); + } + } +} diff --git a/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java b/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java new file mode 100644 index 000000000..ee65d6b7a --- /dev/null +++ b/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.slidingwindow; + +import static org.junit.Assert.assertTrue; + +import io.temporal.testing.TestWorkflowRule; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInfo; +import org.junit.Rule; +import org.junit.Test; + +public class SlidingWindowBatchWorkflowTest { + + private static final int RECORD_COUNT = 15; + private static boolean[] processedRecords = new boolean[RECORD_COUNT]; + + public static class TestRecordProcessorWorkflowImpl implements RecordProcessorWorkflow { + + @Override + public void processRecord(Record r) { + processedRecords[r.getId()] = true; + WorkflowInfo info = Workflow.getInfo(); + String parentId = info.getParentWorkflowId().get(); + SlidingWindowBatchWorkflow parent = + Workflow.newExternalWorkflowStub(SlidingWindowBatchWorkflow.class, parentId); + Workflow.sleep(500); + // Notify parent about record processing completion + parent.reportCompletion(r.getId()); + } + } + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes( + SlidingWindowBatchWorkflowImpl.class, TestRecordProcessorWorkflowImpl.class) + .setActivityImplementations(new RecordLoaderImpl()) + .build(); + + @Test + public void testSlidingWindowBatchWorkflow() { + SlidingWindowBatchWorkflow workflow = + testWorkflowRule.newWorkflowStub(SlidingWindowBatchWorkflow.class); + + ProcessBatchInput input = new ProcessBatchInput(); + input.setPageSize(3); + input.setSlidingWindowSize(7); + input.setOffset(0); + input.setMaximumOffset(RECORD_COUNT); + workflow.processBatch(input); + for (int i = 0; i < RECORD_COUNT; i++) { + assertTrue(processedRecords[i]); + } + } +} From 2c1a7427e41e91c7a33e0d8ffb6480311ccf83c9 Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Mon, 28 Nov 2022 14:27:59 -0500 Subject: [PATCH 033/240] Fix build under the latest JDKs by migrating on the spotless plugin (#390) --- README.md | 5 ++++ build.gradle | 30 +++++++++++-------- docker/buildkite/Dockerfile | 2 +- .../iterator/IteratorBatchWorkflowImpl.java | 4 +-- .../samples/batch/iterator/RecordLoader.java | 2 +- .../batch/iterator/RecordLoaderImpl.java | 6 ++-- .../iterator/RecordProcessorWorkflow.java | 2 +- .../iterator/RecordProcessorWorkflowImpl.java | 2 +- .../{Record.java => SingleRecord.java} | 8 ++--- .../SlidingWindowBatchWorkflowImpl.java | 4 ++- .../IteratorIteratorBatchWorkflowTest.java | 2 +- 11 files changed, 40 insertions(+), 27 deletions(-) rename src/main/java/io/temporal/samples/batch/iterator/{Record.java => SingleRecord.java} (88%) diff --git a/README.md b/README.md index f17c52432..ea4f9b051 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,11 @@ This repository contains sample Workflow applications that demonstrate various c - [IDE Integration](#ide-integration) - [IntelliJ](#intellij) +## Requirements + +- Java 1.8+ for build and runtime +- Java 11+ for development and contribution + ## How to use 1. Clone this repository: diff --git a/build.gradle b/build.gradle index 4097d426b..1635f4974 100644 --- a/build.gradle +++ b/build.gradle @@ -2,16 +2,11 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' - id 'com.github.sherter.google-java-format' version '0.9' id "net.ltgt.errorprone" version "3.0.1" + id 'com.diffplug.spotless' version '6.11.0' apply false } apply plugin: 'java' -apply plugin: 'com.github.sherter.google-java-format' - -googleJavaFormat { - toolVersion (JavaVersion.current().isJava11Compatible() ? '1.15.0' : '1.7') -} java { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -26,7 +21,7 @@ repositories { } dependencies { - implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.0")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.1")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.20.1")) implementation(platform("org.junit:junit-bom:5.9.1")) @@ -62,7 +57,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:1.17.0") testImplementation "junit:junit:4.13.2" - testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.8.1' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.9.0' testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' testImplementation "org.junit.jupiter:junit-jupiter-api" @@ -79,10 +74,6 @@ dependencies { } } -compileJava { - dependsOn 'googleJavaFormat' -} - task execute(type: JavaExec) { main = findProperty("mainClass") ?: "" classpath = sourceSets.main.runtimeClasspath @@ -97,3 +88,18 @@ license { exclude '**/*.json' exclude '**/*.yml' } + +if (JavaVersion.current().isJava11Compatible()) { + // Code should be formatted using the latest googleJavaFormat, but it doesn't support Java <11 since version 1.8 + apply plugin: 'com.diffplug.spotless' + + spotless { + java { + target 'src/*/java/**/*.java' + targetExclude '**/.idea/**' + googleJavaFormat('1.15.0') + } + } + + compileJava.dependsOn 'spotlessApply' +} diff --git a/docker/buildkite/Dockerfile b/docker/buildkite/Dockerfile index f9d74f88d..9a5836a6d 100644 --- a/docker/buildkite/Dockerfile +++ b/docker/buildkite/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:8-focal +FROM eclipse-temurin:11-focal # Git is needed in order to update the dls submodule RUN apt-get update && apt-get install -y wget protobuf-compiler git diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java index 4c46cb268..44a56a5a8 100644 --- a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java @@ -52,10 +52,10 @@ public final class IteratorBatchWorkflowImpl implements IteratorBatchWorkflow { @Override public int processBatch(int pageSize, int offset) { // Loads a page of records - List records = recordLoader.getRecords(pageSize, offset); + List records = recordLoader.getRecords(pageSize, offset); // Starts a child per record asynchrnously. List> results = new ArrayList<>(records.size()); - for (Record record : records) { + for (SingleRecord record : records) { // Uses human friendly child id. String childId = Workflow.getInfo().getWorkflowId() + "/" + record.getId(); RecordProcessorWorkflow processor = diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java b/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java index 77da1e592..9f1974993 100644 --- a/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java +++ b/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java @@ -39,5 +39,5 @@ public interface RecordLoader { * @param pageSize maximum number of records to return. * @return empty list if no more records to process. */ - List getRecords(int pageSize, int offset); + List getRecords(int pageSize, int offset); } diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java b/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java index 389c78967..72fbd0189 100644 --- a/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java +++ b/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java @@ -30,11 +30,11 @@ public final class RecordLoaderImpl implements RecordLoader { public static final int PAGE_COUNT = 5; @Override - public List getRecords(int pageSize, int offset) { - List records = new ArrayList<>(pageSize); + public List getRecords(int pageSize, int offset) { + List records = new ArrayList<>(pageSize); if (offset < pageSize * PAGE_COUNT) { for (int i = 0; i < pageSize; i++) { - records.add(new Record(offset + i)); + records.add(new SingleRecord(offset + i)); } } return records; diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java b/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java index 01df5689e..703716a55 100644 --- a/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java +++ b/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java @@ -28,5 +28,5 @@ public interface RecordProcessorWorkflow { /** Processes a single record */ @WorkflowMethod - void processRecord(Record r); + void processRecord(SingleRecord r); } diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java index d2e22f2af..12535f7aa 100644 --- a/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java @@ -30,7 +30,7 @@ public class RecordProcessorWorkflowImpl implements RecordProcessorWorkflow { private final Random random = Workflow.newRandom(); @Override - public void processRecord(Record r) { + public void processRecord(SingleRecord r) { // Simulate some processing Workflow.sleep(Duration.ofSeconds(random.nextInt(30))); log.info("Processed " + r); diff --git a/src/main/java/io/temporal/samples/batch/iterator/Record.java b/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java similarity index 88% rename from src/main/java/io/temporal/samples/batch/iterator/Record.java rename to src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java index ef1698277..ea40ee807 100644 --- a/src/main/java/io/temporal/samples/batch/iterator/Record.java +++ b/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java @@ -20,15 +20,15 @@ package io.temporal.samples.batch.iterator; /** Record to process. A real application would add a use case specific data. */ -public class Record { +public class SingleRecord { private int id; - public Record(int id) { + public SingleRecord(int id) { this.id = id; } /** JSON deserializer needs it */ - public Record() {} + public SingleRecord() {} public int getId() { return id; @@ -36,6 +36,6 @@ public int getId() { @Override public String toString() { - return "Record{" + "id=" + id + '}'; + return "SingleRecord{" + "id=" + id + '}'; } } diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java index 821308aaf..fafa61ba7 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java @@ -51,7 +51,9 @@ public final class SlidingWindowBatchWorkflowImpl implements SlidingWindowBatchW /** Count of completed record processing child workflows. */ private int progress; - /** @return number of processed records */ + /** + * @return number of processed records + */ @Override public int processBatch(ProcessBatchInput input) { WorkflowInfo info = Workflow.getInfo(); diff --git a/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java b/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java index 9a4346437..648e67cc3 100644 --- a/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java +++ b/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java @@ -36,7 +36,7 @@ public class IteratorIteratorBatchWorkflowTest { public static class TestRecordProcessorWorkflowImpl implements RecordProcessorWorkflow { @Override - public void processRecord(Record r) { + public void processRecord(SingleRecord r) { Workflow.sleep(5000); processedRecords[r.getId()] = true; } From dadaa2c4ffb9a1bf903601a042cc182557fa529d Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Mon, 28 Nov 2022 20:18:21 -0500 Subject: [PATCH 034/240] Address errorprone naming warning (#391) --- build.gradle | 2 +- .../samples/batch/slidingwindow/RecordIterable.java | 12 ++++++------ .../samples/batch/slidingwindow/RecordLoader.java | 2 +- .../batch/slidingwindow/RecordLoaderImpl.java | 6 +++--- .../batch/slidingwindow/RecordProcessorWorkflow.java | 2 +- .../slidingwindow/RecordProcessorWorkflowImpl.java | 4 ++-- .../slidingwindow/{Record.java => SingleRecord.java} | 8 ++++---- .../SlidingWindowBatchWorkflowImpl.java | 6 +++--- .../SlidingWindowBatchWorkflowTest.java | 2 +- 9 files changed, 22 insertions(+), 22 deletions(-) rename src/main/java/io/temporal/samples/batch/slidingwindow/{Record.java => SingleRecord.java} (88%) diff --git a/build.gradle b/build.gradle index 1635f4974..be3f1511e 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.0.1" - id 'com.diffplug.spotless' version '6.11.0' apply false + id 'com.diffplug.spotless' version '6.12.0' apply false } apply plugin: 'java' diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java index 13cf644f6..b9eece15d 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.NotNull; /** Iterable implementation that relies on RecordLoader activity. */ -public class RecordIterable implements Iterable { +public class RecordIterable implements Iterable { /** * Iterator implementation that relies on RecordLoader activity. @@ -37,13 +37,13 @@ public class RecordIterable implements Iterable { *

This code assumes that RecordLoader.getRecords never returns a failure to the workflow. The * real production application might make a different design choice. */ - private class RecordIterator implements Iterator { + private class RecordIterator implements Iterator { /** * The last page of records loaded through RecordLoader activity. The activity returns an empty * page to indicate the end of iteration. */ - private List lastPage; + private List lastPage; /** The offset of the last loaded batch of records. */ private int offset; @@ -67,12 +67,12 @@ public boolean hasNext() { } @Override - public Record next() { + public SingleRecord next() { int size = lastPage.size(); if (size == 0) { throw new NoSuchElementException(); } - Record result = lastPage.get(index++); + SingleRecord result = lastPage.get(index++); if (size == index) { offset += index; index = 0; @@ -106,7 +106,7 @@ public RecordIterable(int pageSize, int initialOffset, int maximumOffset) { @NotNull @Override - public Iterator iterator() { + public Iterator iterator() { return new RecordIterator(); } } diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java index 2969e8d06..f0dbf70bc 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java @@ -32,7 +32,7 @@ public interface RecordLoader { * @param pageSize maximum number of records to return. * @return empty list if no more records to process. */ - List getRecords(int pageSize, int offset); + List getRecords(int pageSize, int offset); /** * Returns the total record count. diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java index 0e86ca357..b97379574 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java @@ -28,11 +28,11 @@ public final class RecordLoaderImpl implements RecordLoader { private static final int TOTAL_COUNT = 300; @Override - public List getRecords(int pageSize, int offset) { - List records = new ArrayList<>(pageSize); + public List getRecords(int pageSize, int offset) { + List records = new ArrayList<>(pageSize); if (offset < TOTAL_COUNT) { for (int i = offset; i < Math.min(offset + pageSize, TOTAL_COUNT); i++) { - records.add(new Record(i)); + records.add(new SingleRecord(i)); } } return records; diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java index 3a99115c0..e4647aa68 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java @@ -31,5 +31,5 @@ public interface RecordProcessorWorkflow { * SlidingWindowBatchWorkflow#reportCompletion(int)} */ @WorkflowMethod - void processRecord(Record r); + void processRecord(SingleRecord r); } diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java index 995a6e0cd..94d294874 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java @@ -31,7 +31,7 @@ public final class RecordProcessorWorkflowImpl implements RecordProcessorWorkflo private final Random random = Workflow.newRandom(); @Override - public void processRecord(Record r) { + public void processRecord(SingleRecord r) { processRecordImpl(r); // This workflow is always expected to have a parent. // But for unit testing it might be useful to skip the notification. @@ -46,7 +46,7 @@ public void processRecord(Record r) { } /** Application specific record processing logic goes here. */ - private void processRecordImpl(Record r) { + private void processRecordImpl(SingleRecord r) { // Simulate some processing Workflow.sleep(Duration.ofSeconds(random.nextInt(10))); log.info("Processed " + r); diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/Record.java b/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java similarity index 88% rename from src/main/java/io/temporal/samples/batch/slidingwindow/Record.java rename to src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java index 3938fc098..ab2f29636 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/Record.java +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java @@ -20,15 +20,15 @@ package io.temporal.samples.batch.slidingwindow; /** Record to process. */ -public class Record { +public class SingleRecord { private int id; - public Record(int id) { + public SingleRecord(int id) { this.id = id; } /** Needed for JSON deserialization. */ - public Record() {} + public SingleRecord() {} public int getId() { return id; @@ -36,6 +36,6 @@ public int getId() { @Override public String toString() { - return "Record{" + "id=" + id + '}'; + return "SingleRecord{" + "id=" + id + '}'; } } diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java index fafa61ba7..91b6d9955 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java @@ -69,10 +69,10 @@ public int processBatch(ProcessBatchInput input) { int maximumOffset = input.getMaximumOffset(); int slidingWindowSize = input.getSlidingWindowSize(); - Iterable records = new RecordIterable(pageSize, offset, maximumOffset); + Iterable records = new RecordIterable(pageSize, offset, maximumOffset); List> childrenStartedByThisRun = new ArrayList<>(); - Iterator recordIterator = records.iterator(); + Iterator recordIterator = records.iterator(); while (true) { // After starting slidingWindowSize children blocks until a completion signal is received. Workflow.await(() -> currentRecords.size() < slidingWindowSize); @@ -82,7 +82,7 @@ public int processBatch(ProcessBatchInput input) { Workflow.await(() -> currentRecords.size() == 0); return offset + childrenStartedByThisRun.size(); } - Record record = recordIterator.next(); + SingleRecord record = recordIterator.next(); // Uses ParentClosePolicy ABANDON to ensure that children survive continue-as-new of a parent. // Assigns user-friendly child workflow id. diff --git a/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java b/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java index ee65d6b7a..2746e09cd 100644 --- a/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java +++ b/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java @@ -35,7 +35,7 @@ public class SlidingWindowBatchWorkflowTest { public static class TestRecordProcessorWorkflowImpl implements RecordProcessorWorkflow { @Override - public void processRecord(Record r) { + public void processRecord(SingleRecord r) { processedRecords[r.getId()] = true; WorkflowInfo info = Workflow.getInfo(); String parentId = info.getParentWorkflowId().get(); From d1b2f8c34051e785eeff5f28128e90220eceff7e Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Thu, 1 Dec 2022 11:32:33 -0800 Subject: [PATCH 035/240] Heartbeating activity batch sample (#392) The sample demonstrates how to process a batch of records by a single heartbeating activity. --- README.md | 2 + .../HeartbeatingActivityBatchStarter.java | 46 +++++++++++ .../HeartbeatingActivityBatchWorker.java | 49 +++++++++++ .../HeartbeatingActivityBatchWorkflow.java | 35 ++++++++ ...HeartbeatingActivityBatchWorkflowImpl.java | 57 +++++++++++++ .../batch/heartbeatingactivity/README.md | 23 ++++++ .../heartbeatingactivity/RecordLoader.java | 40 +++++++++ .../RecordLoaderImpl.java | 36 +++++++++ .../heartbeatingactivity/RecordProcessor.java | 31 +++++++ .../RecordProcessorActivity.java | 29 +++++++ .../RecordProcessorActivityImpl.java | 81 +++++++++++++++++++ .../RecordProcessorImpl.java | 41 ++++++++++ .../heartbeatingactivity/SingleRecord.java | 41 ++++++++++ ...HeartbeatingActivityBatchWorkflowTest.java | 59 ++++++++++++++ .../IteratorIteratorBatchWorkflowTest.java | 4 +- .../SlidingWindowBatchWorkflowTest.java | 12 ++- 16 files changed, 583 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java create mode 100644 src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java create mode 100644 src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java diff --git a/README.md b/README.md index ea4f9b051..bc74fed49 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,8 @@ All tests are available under [src/test/java](https://github.com/temporalio/samp - [**Polling Services**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion +- [**Heartbeating Activity Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/batch/heartbeatingactivity): Batch job implementation using a heartbeating activity. + - [**Iterator Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/batch/iterator): Batch job implementation using the workflow iterator pattern. - [**Sliding Window Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java new file mode 100644 index 000000000..57ec84bb2 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import static io.temporal.samples.batch.heartbeatingactivity.HeartbeatingActivityBatchWorker.TASK_QUEUE; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; + +/** Starts a single execution of HeartbeatingActivityBatchWorkflow. */ +public class HeartbeatingActivityBatchStarter { + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient workflowClient = WorkflowClient.newInstance(service); + WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build(); + HeartbeatingActivityBatchWorkflow batchWorkflow = + workflowClient.newWorkflowStub(HeartbeatingActivityBatchWorkflow.class, options); + WorkflowExecution execution = WorkflowClient.start(batchWorkflow::processBatch); + System.out.println( + "Started batch workflow. WorkflowId=" + + execution.getWorkflowId() + + ", RunId=" + + execution.getRunId()); + System.exit(0); + } +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java new file mode 100644 index 000000000..fad30f414 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +/** + * A worker process that hosts implementations of HeartbeatingActivityBatchWorkflow and + * RecordProcessorActivity. + */ +public final class HeartbeatingActivityBatchWorker { + + static final String TASK_QUEUE = "HeartbeatingActivityBatch"; + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(TASK_QUEUE); + + worker.registerWorkflowImplementationTypes(HeartbeatingActivityBatchWorkflowImpl.class); + + worker.registerActivitiesImplementations( + new RecordProcessorActivityImpl(new RecordLoaderImpl(), new RecordProcessorImpl())); + factory.start(); + System.out.println("Worker started for task queue: " + TASK_QUEUE); + } +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java new file mode 100644 index 000000000..8d9d9f061 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HeartbeatingActivityBatchWorkflow { + + /** + * Processes the batch of records. + * + * @return total number of processed records. + */ + @WorkflowMethod + int processBatch(); +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java new file mode 100644 index 000000000..946f3fa20 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +/** + * A sample implementation of processing a batch by an activity. + * + *

An activity can run as long as needed. It reports that it is still alive through heartbeat. If + * the worker is restarted the activity is retried after the heartbeat timeout. Temporal allows + * store data in heartbeat _details_. These details are available to the next activity attempt. The + * progress of the record processing is stored in the details to avoid reprocessing records from the + * beginning on failures. + */ +public final class HeartbeatingActivityBatchWorkflowImpl + implements HeartbeatingActivityBatchWorkflow { + + /** + * Activity that is used to process batch records. The start-to-close timeout is set to a high + * value to support large batch sizes. Heartbeat timeout is required to quickly restart the + * activity in case of failures. The heartbeat timeout is also needed to record heartbeat details + * at the service. + */ + private final RecordProcessorActivity recordProcessor = + Workflow.newActivityStub( + RecordProcessorActivity.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofHours(1)) + .setHeartbeatTimeout(Duration.ofSeconds(10)) + .build()); + + @Override + public int processBatch() { + // No special logic needed here as activity is retried automatically by the service. + return recordProcessor.processRecords(); + } +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md new file mode 100644 index 000000000..e4bc90071 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md @@ -0,0 +1,23 @@ +A sample implementation of processing a batch by an activity. + +An activity can run as long as needed. It reports that it is still alive through heartbeat. If the worker is restarted +the activity is retried after the heartbeat timeout. Temporal allows store data in heartbeat _details_. These details +are available to the next activity attempt. The progress of the record processing is stored in the details to avoid +reprocessing records from the beginning on failures. + +#### Running the Iterator Batch Sample + +The sample has two executables. Execute each command in a separate terminal window. + +The first command runs the Worker that hosts the Workflow and Activity Executions. Restart the worker while the batch is +executing to see how activity timeout and retry work. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.batch.heartbeatingactivity.HeartbeatingActivityBatchWorker +``` + +The second command start the Workflow Execution. Each time the command runs, it starts a new Workflow Execution. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.batch.heartbeatingactivity.HeartbeatingActivityBatchStarter +``` diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java new file mode 100644 index 000000000..b5e49918f --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import java.util.Optional; + +/** + * Helper class that is used to iterate over a list of records. + * + *

A specific implementation depends on a use case. For example, it can execute an SQL DB query + * or read a comma delimited file. More complex use cases would need passing a different type of + * offset parameter. + */ +public interface RecordLoader { + + /** + * Returns the next record. + * + * @param offset offset of the next record. + * @return Record at the offset. Empty optional if offset exceeds the dataset size. + */ + Optional getRecord(int offset); +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java new file mode 100644 index 000000000..818507743 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import java.util.Optional; + +/** Fake implementation of RecordLoader. */ +public final class RecordLoaderImpl implements RecordLoader { + + static final int RECORD_COUNT = 1000; + + @Override + public Optional getRecord(int offset) { + if (offset >= RECORD_COUNT) { + return Optional.empty(); + } + return Optional.of(new SingleRecord(offset)); + } +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java new file mode 100644 index 000000000..6aa0241da --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +/** A helper class that implements record processing. */ +public interface RecordProcessor { + + /** + * Processes a single record. + * + * @param record record to process + */ + void processRecord(SingleRecord record); +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java new file mode 100644 index 000000000..cc0678f8c --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface RecordProcessorActivity { + + /** Processes all records in the dataset */ + int processRecords(); +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java new file mode 100644 index 000000000..4ec9b1bb6 --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import io.temporal.activity.Activity; +import io.temporal.activity.ActivityExecutionContext; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * RecordProcessorActivity implementation. + * + *

It relies on RecordLoader to iterate over set of records and process them one by one. The + * heartbeat is used to remember offset. On activity retry the data from the last recorded heartbeat + * is used to minimize the number of records that are reprocessed. Note that not every heartbeat + * call is sent to the service. The frequency of the heartbeat service calls depends on the + * heartbeat timeout the activity was scheduled with. If no heartbeat timeout is not set then no + * heartbeat is ever sent to the service. + * + *

The biggest advantage of this approach is efficiency. It uses very few Temporal resources. + * + *

The biggest limitation of this approach is that it cannot deal with record processing + * failures. The only options are either failing the whole batch or skip the record. While it is + * possible to build additional logic to record failed records somewhere the experience is not + * seamless. + */ +public class RecordProcessorActivityImpl implements RecordProcessorActivity { + + private static final Logger log = LoggerFactory.getLogger(RecordProcessorActivityImpl.class); + + private final RecordLoader recordLoader; + + private final RecordProcessor recordProcessor; + + public RecordProcessorActivityImpl(RecordLoader recordLoader, RecordProcessor recordProcessor) { + this.recordLoader = recordLoader; + this.recordProcessor = recordProcessor; + } + + @Override + public int processRecords() { + // On activity retry load the last reported offset from the heartbeat details. + ActivityExecutionContext context = Activity.getExecutionContext(); + Optional heartbeatDetails = context.getHeartbeatDetails(Integer.class); + int offset = heartbeatDetails.orElse(0); + log.info("Activity processRecords started with offset=" + offset); + // This sample implementation processes records one by one. + // If needed it can be changed to use a pool of threads or asynchronous code to process multiple + // such records in parallel. + while (true) { + Optional record = recordLoader.getRecord(offset); + if (!record.isPresent()) { + return offset; + } + recordProcessor.processRecord(record.get()); + // Report that activity is still alive. The assumption is that each record takes less time + // to process than the heartbeat timeout. + // Leverage heartbeat details to record offset. + context.heartbeat(offset); + offset++; + } + } +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java new file mode 100644 index 000000000..91916b30e --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Fake record processor implementation. */ +public final class RecordProcessorImpl implements RecordProcessor { + + private static final Logger log = LoggerFactory.getLogger(RecordProcessorImpl.class); + + @Override + public void processRecord(SingleRecord record) { + // Fake processing logic + try { + Thread.sleep(100); + log.info("Processed " + record); + } catch (InterruptedException ignored) { + return; + } + return; + } +} diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java new file mode 100644 index 000000000..bec3fdd6c --- /dev/null +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +/** Record to process. A real application would add a use case specific data. */ +public class SingleRecord { + private int id; + + public SingleRecord(int id) { + this.id = id; + } + + /** JSON deserializer needs it */ + public SingleRecord() {} + + public int getId() { + return id; + } + + @Override + public String toString() { + return "Record{" + "id=" + id + '}'; + } +} diff --git a/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java b/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java new file mode 100644 index 000000000..1de5d5360 --- /dev/null +++ b/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.batch.heartbeatingactivity; + +import static io.temporal.samples.batch.heartbeatingactivity.RecordLoaderImpl.RECORD_COUNT; +import static org.junit.Assert.assertTrue; + +import io.temporal.testing.TestWorkflowRule; +import org.junit.Rule; +import org.junit.Test; + +public class HeartbeatingActivityBatchWorkflowTest { + private static boolean[] processedRecords = new boolean[RECORD_COUNT]; + + public static class TestRecordProcessorImpl implements RecordProcessor { + + @Override + public void processRecord(SingleRecord r) { + processedRecords[r.getId()] = true; + } + } + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(HeartbeatingActivityBatchWorkflowImpl.class) + .setActivityImplementations( + new RecordProcessorActivityImpl( + new RecordLoaderImpl(), new TestRecordProcessorImpl())) + .build(); + + @Test + public void testBatchWorkflow() { + HeartbeatingActivityBatchWorkflow workflow = + testWorkflowRule.newWorkflowStub(HeartbeatingActivityBatchWorkflow.class); + workflow.processBatch(); + + for (int i = 0; i < processedRecords.length; i++) { + assertTrue(processedRecords[i]); + } + } +} diff --git a/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java b/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java index 648e67cc3..edc6ec250 100644 --- a/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java +++ b/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java @@ -52,9 +52,9 @@ public void processRecord(SingleRecord r) { @Test public void testBatchWorkflow() { IteratorBatchWorkflow workflow = testWorkflowRule.newWorkflowStub(IteratorBatchWorkflow.class); - workflow.processBatch(3, 0); + workflow.processBatch(PAGE_SIZE, 0); - for (int i = 0; i < PAGE_SIZE; i++) { + for (int i = 0; i < processedRecords.length; i++) { assertTrue(processedRecords[i]); } } diff --git a/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java b/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java index 2746e09cd..ae48290e2 100644 --- a/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java +++ b/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java @@ -43,7 +43,17 @@ public void processRecord(SingleRecord r) { Workflow.newExternalWorkflowStub(SlidingWindowBatchWorkflow.class, parentId); Workflow.sleep(500); // Notify parent about record processing completion - parent.reportCompletion(r.getId()); + // Needs to retry due to a continue-as-new atomicity + // bug in the testservice: + // https://github.com/temporalio/sdk-java/issues/1538 + while (true) { + try { + parent.reportCompletion(r.getId()); + break; + } catch (Exception e) { + continue; + } + } } } From 3e72d933715590000c2c126f6d2043a9c1cca82c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Dec 2022 20:34:06 -0500 Subject: [PATCH 036/240] Bump opentelemetry-bom from 1.20.1 to 1.21.0 (#395) Bumps [opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.20.1 to 1.21.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.20.1...v1.21.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index be3f1511e..c196e30e5 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ repositories { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.1")) - implementation(platform("io.opentelemetry:opentelemetry-bom:1.20.1")) + implementation(platform("io.opentelemetry:opentelemetry-bom:1.21.0")) implementation(platform("org.junit:junit-bom:5.9.1")) implementation "io.temporal:temporal-sdk:1.17.0" From 53ea7f0baae593ea2bd4419209ef4af0cf4a90a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Dec 2022 20:34:48 -0500 Subject: [PATCH 037/240] Bump mockito-core from 4.9.0 to 4.10.0 (#397) Bumps [mockito-core](https://github.com/mockito/mockito) from 4.9.0 to 4.10.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.9.0...v4.10.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c196e30e5..f3de37db6 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:1.17.0") testImplementation "junit:junit:4.13.2" - testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.9.0' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.10.0' testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' testImplementation "org.junit.jupiter:junit-jupiter-api" From 0ade1545d69021916664431f8cf731166474ac9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Jan 2023 20:49:16 -0500 Subject: [PATCH 038/240] Bump mockito-core from 4.10.0 to 4.11.0 (#398) Bumps [mockito-core](https://github.com/mockito/mockito) from 4.10.0 to 4.11.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.10.0...v4.11.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f3de37db6..8a511a36d 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:1.17.0") testImplementation "junit:junit:4.13.2" - testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.10.0' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.11.0' testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' testImplementation "org.junit.jupiter:junit-jupiter-api" From 89643171bc9249110d14950d7dd02a426e1f8dbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Jan 2023 20:49:35 -0500 Subject: [PATCH 039/240] Bump com.diffplug.spotless from 6.12.0 to 6.12.1 (#399) Bumps com.diffplug.spotless from 6.12.0 to 6.12.1. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8a511a36d..54f8cea81 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.0.1" - id 'com.diffplug.spotless' version '6.12.0' apply false + id 'com.diffplug.spotless' version '6.12.1' apply false } apply plugin: 'java' From 348c681d74c726c463ed25169f2201fc4256660c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Jan 2023 20:49:56 -0500 Subject: [PATCH 040/240] Bump error_prone_core from 2.16 to 2.17.0 (#400) Bumps [error_prone_core](https://github.com/google/error-prone) from 2.16 to 2.17.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.16...v2.17.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 54f8cea81..f5870e6ef 100644 --- a/build.gradle +++ b/build.gradle @@ -67,9 +67,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.16') + errorprone('com.google.errorprone:error_prone_core:2.17.0') } else { - errorprone('com.google.errorprone:error_prone_core:2.10.0') + errorprone('com.google.errorprone:error_prone_core:2.17.0') } } } From 5fe9f2a5be88726e07023b946fd0724d7927e932 Mon Sep 17 00:00:00 2001 From: Samantha Santiago Date: Fri, 6 Jan 2023 08:56:53 -0600 Subject: [PATCH 041/240] Tw 219 update links samples java (#401) * master to main * links mostly fine. Made capitalization fixes --- README.md | 90 +++++++++---------- docker/buildkite/README.md | 2 +- .../io/temporal/samples/asyncchild/README.md | 6 +- .../batch/heartbeatingactivity/README.md | 14 +-- .../temporal/samples/batch/iterator/README.md | 11 +-- .../samples/batch/slidingwindow/README.md | 16 ++-- .../io/temporal/samples/bookingsaga/README.md | 2 +- .../java/io/temporal/samples/dsl/README.md | 2 +- .../samples/getresultsasync/README.md | 2 +- .../temporal/samples/listworkflows/README.md | 6 +- .../io/temporal/samples/moneybatch/README.md | 6 +- .../samples/payloadconverter/crypto/README.md | 3 +- .../samples/peractivityoptions/README.md | 2 +- .../samples/polling/frequent/README.md | 2 +- .../samples/polling/infrequent/README.md | 14 +-- .../polling/periodicsequence/README.md | 13 +-- .../samples/terminateworkflow/README.md | 3 +- 17 files changed, 95 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index bc74fed49..a8e5c2462 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ enabled on the Temporal Server side. To do this you can run locally with: docker-compose -f docker-compose-cass-es.yml up Alternatively you could install the Temporal Server on Kubernetes / Minicube using the [Temporal Helm charts](https://github.com/temporalio/helm-charts). -Note that in this case you should use the [Temporal CLI (tctl)](https://docs.temporal.io/docs/system-tools/tctl/) tool to create a namespace called "default": +Note that in this case you should use the [Temporal CLI (tctl)](https://docs.temporal.io/tctl-v1/) tool to create a namespace called "default": tctl --ns default n re @@ -93,84 +93,84 @@ The following section lists all available samples. Click on the sample link to view the README, which contains instructions on how to run them. Each sample has an associated unit test which demonstrates the use of the Temporal Java SDK testing API. -All tests are available under [src/test/java](https://github.com/temporalio/samples-java/tree/master/src/test/java/io/temporal/samples) +All tests are available under [src/test/java](https://github.com/temporalio/samples-java/tree/main/src/test/java/io/temporal/samples) ### Hello samples -- [**Hello**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/hello): This sample includes a number of individual Workflows that can be executed independently. Each one demonstrates something specific. - - [**HelloActivity**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloActivity.java): Demonstrates a Workflow Definition that executes a single Activity. - - [**HelloActivityRetry**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java): Demonstrates how to Retry an Activity Execution. - - [**HelloActivityExclusiveChoice**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java): Demonstrates how to execute Activities based on dynamic input. - - [**HelloAsync**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloAsync.java): Demonstrates how to execute Activities asynchronously and wait for them using Promises. - - [**HelloParallelActivity**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java): Demonstrates how to execute multiple Activities in parallel, asynchronously, and wait for them using `Promise.allOf`. - - [**HelloAsyncActivityCompletion**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java): Demonstrates how to complete an Activity Execution asynchronously. - - [**HelloAsyncLambda**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java): Demonstrates how to execute part of a Workflow asynchronously in a separate task (thread). - - [**HelloCancellationScope**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java): Demonstrates how to explicitly cancel parts of a Workflow Execution. - - [**HelloDetachedCancellationScope**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java): Demonstrates how to execute cleanup code after a Workflow Execution has been explicitly cancelled. - - [**HelloChild**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloChild.java): Demonstrates how to execute a simple Child Workflow. - - [**HelloCron**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloCron.java): Demonstrates how to execute a Workflow according to a cron schedule. - - [**HelloDynamic**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloDynamic.java): Demonstrates how to use `DynamicWorkflow` and `DynamicActivity` interfaces. - - [**HelloPeriodic**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloPeriodic.java): Demonstrates the use of the Continue-As-New feature. - - [**HelloException**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloException.java): Demonstrates how to handle exception propagation and wrapping. - - [**HelloLocalActivity**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java): Demonstrates the use of a [Local Activity](https://docs.temporal.io/docs/jargon/mesh/#local-activity). - - [**HelloPolymorphicActivity**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java): Demonstrates Activity Definitions that extend a common interface. - - [**HelloQuery**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloQuery.java): Demonstrates how to Query the state of a Workflow Execution. - - [**HelloSignal**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloSignal.java): Demonstrates how to send and handle a Signal. - - [**HelloSaga**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloSaga.java): Demonstrates how to use the SAGA feature. - - [**HelloSearchAttributes**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java): Demonstrates how to add custom Search Attributes to Workflow Executions. - - [**HelloSideEffect**](https://github.com/temporalio/samples-java/blob/master/src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. +- [**Hello**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/hello): This sample includes a number of individual Workflows that can be executed independently. Each one demonstrates something specific. + - [**HelloActivity**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloActivity.java): Demonstrates a Workflow Definition that executes a single Activity. + - [**HelloActivityRetry**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java): Demonstrates how to Retry an Activity Execution. + - [**HelloActivityExclusiveChoice**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java): Demonstrates how to execute Activities based on dynamic input. + - [**HelloAsync**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloAsync.java): Demonstrates how to execute Activities asynchronously and wait for them using Promises. + - [**HelloParallelActivity**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java): Demonstrates how to execute multiple Activities in parallel, asynchronously, and wait for them using `Promise.allOf`. + - [**HelloAsyncActivityCompletion**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java): Demonstrates how to complete an Activity Execution asynchronously. + - [**HelloAsyncLambda**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java): Demonstrates how to execute part of a Workflow asynchronously in a separate task (thread). + - [**HelloCancellationScope**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java): Demonstrates how to explicitly cancel parts of a Workflow Execution. + - [**HelloDetachedCancellationScope**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java): Demonstrates how to execute cleanup code after a Workflow Execution has been explicitly cancelled. + - [**HelloChild**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloChild.java): Demonstrates how to execute a simple Child Workflow. + - [**HelloCron**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloCron.java): Demonstrates how to execute a Workflow according to a cron schedule. + - [**HelloDynamic**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloDynamic.java): Demonstrates how to use `DynamicWorkflow` and `DynamicActivity` interfaces. + - [**HelloPeriodic**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloPeriodic.java): Demonstrates the use of the Continue-As-New feature. + - [**HelloException**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloException.java): Demonstrates how to handle exception propagation and wrapping. + - [**HelloLocalActivity**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java): Demonstrates the use of a [Local Activity](https://docs.temporal.io/docs/jargon/mesh/#local-activity). + - [**HelloPolymorphicActivity**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java): Demonstrates Activity Definitions that extend a common interface. + - [**HelloQuery**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloQuery.java): Demonstrates how to Query the state of a Workflow Execution. + - [**HelloSignal**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloSignal.java): Demonstrates how to send and handle a Signal. + - [**HelloSaga**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloSaga.java): Demonstrates how to use the SAGA feature. + - [**HelloSearchAttributes**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java): Demonstrates how to add custom Search Attributes to Workflow Executions. + - [**HelloSideEffect**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. ### Scenario-based samples -- [**File Processing Sample**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/fileprocessing): Demonstrates how to route tasks to specific Workers. This sample has a set of Activities that download a file, processes it, and uploads the result to a destination. Any Worker can execute the first Activity. However, the second and third Activities must be executed on the same host as the first one. +- [**File Processing Sample**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/fileprocessing): Demonstrates how to route tasks to specific Workers. This sample has a set of Activities that download a file, processes it, and uploads the result to a destination. Any Worker can execute the first Activity. However, the second and third Activities must be executed on the same host as the first one. -- [**Booking SAGA**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/bookingsaga): Demonstrates Temporals take on the Camunda BPMN "trip booking" example. +- [**Booking SAGA**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/bookingsaga): Demonstrates Temporals take on the Camunda BPMN "trip booking" example. -- [**Money Transfer**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/moneytransfer): Demonstrates the use of a dedicated Activity Worker. +- [**Money Transfer**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/moneytransfer): Demonstrates the use of a dedicated Activity Worker. -- [**Money Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/moneybatch): Demonstrates a situation where a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. This sample can be easily extended to perform a payment based on more complex criteria, such as at a specific time or an accumulated amount. The sample also demonstrates how to Signal the Workflow when it executes (*Signal with start*). If the Workflow is already executing, it just receives the Signal. If it is not executing, then the Workflow executes first, and then the Signal is delivered to it. *Signal with start* is a "lazy" way to execute Workflows when Signaling them. +- [**Money Batch**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/moneybatch): Demonstrates a situation where a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. This sample can be easily extended to perform a payment based on more complex criteria, such as at a specific time or an accumulated amount. The sample also demonstrates how to Signal the Workflow when it executes (*Signal with start*). If the Workflow is already executing, it just receives the Signal. If it is not executing, then the Workflow executes first, and then the Signal is delivered to it. *Signal with start* is a "lazy" way to execute Workflows when Signaling them. -- [**Customer Application Approval DSL**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/dsl): Demonstrates execution of a customer application approval workflow defined in a DSL (like JSON or YAML) +- [**Customer Application Approval DSL**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/dsl): Demonstrates execution of a customer application approval workflow defined in a DSL (like JSON or YAML) -- [**Polling Services**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion +- [**Polling Services**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion -- [**Heartbeating Activity Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/batch/heartbeatingactivity): Batch job implementation using a heartbeating activity. +- [**Heartbeating Activity Batch**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/batch/heartbeatingactivity): Batch job implementation using a heartbeating activity. -- [**Iterator Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/batch/iterator): Batch job implementation using the workflow iterator pattern. +- [**Iterator Batch**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/batch/iterator): Batch job implementation using the workflow iterator pattern. -- [**Sliding Window Batch**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. +- [**Sliding Window Batch**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. ### API demonstrations -- [**Updatable Timer**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. +- [**Updatable Timer**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. -- [**Workflow Interceptor**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/interceptor): Demonstrates how to create and register a simple Workflow Interceptor. +- [**Workflow Interceptor**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/interceptor): Demonstrates how to create and register a simple Workflow Interceptor. -- [**List Workflows**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/listworkflows): Demonstrates the use of custom search attributes and ListWorkflowExecutionsRequest with custom queries. +- [**List Workflows**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/listworkflows): Demonstrates the use of custom search attributes and ListWorkflowExecutionsRequest with custom queries. -- [**Payload Converter - CloudEvents**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/payloadconverter/cloudevents): Demonstrates the use of a custom payload converter for CloudEvents. +- [**Payload Converter - CloudEvents**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/payloadconverter/cloudevents): Demonstrates the use of a custom payload converter for CloudEvents. -- [**Payload Converter - Crypto**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/payloadconverter/crypto): Demonstrates the use of a custom payload converter using jackson-json-crypto. +- [**Payload Converter - Crypto**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/payloadconverter/crypto): Demonstrates the use of a custom payload converter using jackson-json-crypto. -- [**Async Child Workflow**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/asyncchild): Demonstrates how to invoke a child workflow async, that can complete after parent workflow is already completed. +- [**Async Child Workflow**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/asyncchild): Demonstrates how to invoke a child workflow async, that can complete after parent workflow is already completed. -- [**Terminate Workflow**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/terminateworkflow): Demonstrates how to terminate a workflow using client API. +- [**Terminate Workflow**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/terminateworkflow): Demonstrates how to terminate a workflow using client API. -- [**Get Workflow Results Async**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/getresultsasync): Demonstrates how to start and get workflow results in async manner. +- [**Get Workflow Results Async**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/getresultsasync): Demonstrates how to start and get workflow results in async manner. -- [**Per Activity Type Options**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/peractivityoptions): Demonstrates how to set per Activity type options. +- [**Per Activity Type Options**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/peractivityoptions): Demonstrates how to set per Activity type options. -- [**Configure WorkflowClient to use mTLS**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/ssl): Demonstrates how to configure WorkflowClient when using mTLS. +- [**Configure WorkflowClient to use mTLS**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/ssl): Demonstrates how to configure WorkflowClient when using mTLS. ### SDK Metrics -- [**Set up SDK metrics**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics. +- [**Set up SDK metrics**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics. ### Tracing Support -- [**Set up OpenTracing and/or OpenTelemetry with Jaeger**](https://github.com/temporalio/samples-java/tree/master/src/main/java/io/temporal/samples/tracing): Demonstrates how to set up OpenTracing and/or OpenTelemetry and view traces using Jaeger. +- [**Set up OpenTracing and/or OpenTelemetry with Jaeger**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/tracing): Demonstrates how to set up OpenTracing and/or OpenTelemetry and view traces using Jaeger. diff --git a/docker/buildkite/README.md b/docker/buildkite/README.md index 81d6e227f..42153a4ed 100644 --- a/docker/buildkite/README.md +++ b/docker/buildkite/README.md @@ -14,6 +14,6 @@ docker-compose -f docker/buildkite/docker-compose.yaml run unit-test Note that BuildKite will run basically the same commands. ## Testing the build in BuildKite -Creating a PR against the master branch will trigger the BuildKite +Creating a PR against the main branch will trigger the BuildKite build. Members of the Temporal team can view the build pipeline here: https://buildkite.com/temporal/java-samples diff --git a/src/main/java/io/temporal/samples/asyncchild/README.md b/src/main/java/io/temporal/samples/asyncchild/README.md index 45bd9e134..000046afe 100644 --- a/src/main/java/io/temporal/samples/asyncchild/README.md +++ b/src/main/java/io/temporal/samples/asyncchild/README.md @@ -1,9 +1,7 @@ # Async Child Workflow execution -The sample demonstrates shows how to invoke a child workflow -async. -The child workflow is allowed to complete its execution -even after the parent workflow completes. +The sample demonstrates shows how to invoke a Child Workflow asynchronously. +The Child Workflow is allowed to complete its execution even after the Parent Workflow completes. ```bash ./gradlew -q execute -PmainClass=io.temporal.samples.asyncchild.Starter diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md index e4bc90071..5c5b511f0 100644 --- a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md +++ b/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md @@ -1,9 +1,13 @@ -A sample implementation of processing a batch by an activity. +A sample implementation of processing a batch by an Activity. -An activity can run as long as needed. It reports that it is still alive through heartbeat. If the worker is restarted -the activity is retried after the heartbeat timeout. Temporal allows store data in heartbeat _details_. These details -are available to the next activity attempt. The progress of the record processing is stored in the details to avoid -reprocessing records from the beginning on failures. +An Activity can run as long as needed. +It reports that it is still alive through Heartbeat. + +If the Worker is restarted, the Activity is retried after the Heartbeat Timeout. + +Temporal allows store data in Heartbeat _details_. +These details are available to the next Activity attempt. +The progress of the record processing is stored in the details to avoid reprocessing records from the beginning on failures. #### Running the Iterator Batch Sample diff --git a/src/main/java/io/temporal/samples/batch/iterator/README.md b/src/main/java/io/temporal/samples/batch/iterator/README.md index bde0cccb5..5ec3d705a 100644 --- a/src/main/java/io/temporal/samples/batch/iterator/README.md +++ b/src/main/java/io/temporal/samples/batch/iterator/README.md @@ -1,9 +1,10 @@ -A sample implementation of the workflow iterator pattern. +A sample implementation of the Workflow iterator pattern. -A workflow starts a configured number of child workflows in parallel. Each child processes a single record. After all -children complete the parent calls continue-as-new and starts the children for the next page of records. This allows -processing a set of records of any size. The advantage of this approach is simplicity. The main disadvantage is that it -processes records in batches, with each batch waiting for the slowest child workflow. +A workflow starts a configured number of Child Workflows in parallel. Each child processes a single record. +After all children complete, the parent calls continue-as-new and starts the children for the next page of records. + +This allows processing a set of records of any size. The advantage of this approach is simplicity. +The main disadvantage is that it processes records in batches, with each batch waiting for the slowest child workflow. A variation of this pattern runs activities instead of child workflows. diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/README.md b/src/main/java/io/temporal/samples/batch/slidingwindow/README.md index d32aef7b4..89ab80ced 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/README.md +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/README.md @@ -1,12 +1,12 @@ -A sample implementation of a batch processing workflow that maintains a sliding window of record processing workflows. +A sample implementation of a batch processing Workflow that maintains a sliding window of record processing Workflows. -A workflow starts a configured number of child workflows in parallel. Each child processes a single record. When a child -completes a new child immediately started. A parent workflow calls continue-as-new after starting a preconfigured number -of children. A child completion is reported through a signal as a parent cannot directly wait for a child started by a -previous run. +A Workflow starts a configured number of Child Workflows in parallel. Each child processes a single record. +When a child completes a new child immediately started. -Multiple instances of SlidingWindowBatchWorkflow run in parallel each processing a subset of records to support higher -total rate of processing. +A Parent Workflow calls continue-as-new after starting a preconfigured number of children. +A child completion is reported through a Signal as a parent cannot directly wait for a child started by a previous run. + +Multiple instances of SlidingWindowBatchWorkflow run in parallel each processing a subset of records to support higher total rate of processing. #### Running the Sliding Window Batch Sample @@ -22,7 +22,7 @@ Note that `Caused by: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Unhandle are expected and benign. They ensure that signals are not lost when there is a race condition between workflow calling continue-as-new and receiving a signal. If these messages appear too frequently consider increasing the number of partitions parameter passed to `BatchWorkflow.processBatch`. They will completely disappear -when [Issue1289](https://github.com/temporalio/temporal/issues/1289) is implemented. +when [Issue 1289](https://github.com/temporalio/temporal/issues/1289) is implemented. The second command start the BatchWorkflow Execution. Each time the command runs, it starts a new BatchWorkflow Execution. diff --git a/src/main/java/io/temporal/samples/bookingsaga/README.md b/src/main/java/io/temporal/samples/bookingsaga/README.md index 612e0b836..d15e563a8 100644 --- a/src/main/java/io/temporal/samples/bookingsaga/README.md +++ b/src/main/java/io/temporal/samples/bookingsaga/README.md @@ -8,4 +8,4 @@ Run the following command to start the sample: ./gradlew -q execute -PmainClass=io.temporal.samples.bookingsaga.TripBookingSaga ``` -Sample unit testing: [TripBookingWorkflowTest](https://github.com/temporalio/samples-java/blob/master/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java) +Sample unit testing: [TripBookingWorkflowTest](https://github.com/temporalio/samples-java/blob/main/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java) diff --git a/src/main/java/io/temporal/samples/dsl/README.md b/src/main/java/io/temporal/samples/dsl/README.md index 838849595..476d3a5d4 100644 --- a/src/main/java/io/temporal/samples/dsl/README.md +++ b/src/main/java/io/temporal/samples/dsl/README.md @@ -17,7 +17,7 @@ This sample runs the following DSL workflows: 6. [`bankingtransactionssubflow/childworkflow.json`](/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json) Note that most DSLs, including Serverless Workflow DSL used in this sample represent -their workflow data as JSON. As such manipulation of this data is done via expression languages +their Workflow data as JSON. As such manipulation of this data is done via expression languages that specilize in manipulating JSON. In this case we use `jq`. You can plug in your expression language of choice. diff --git a/src/main/java/io/temporal/samples/getresultsasync/README.md b/src/main/java/io/temporal/samples/getresultsasync/README.md index dfce9709f..b97aeed67 100644 --- a/src/main/java/io/temporal/samples/getresultsasync/README.md +++ b/src/main/java/io/temporal/samples/getresultsasync/README.md @@ -1,7 +1,7 @@ # Get Workflow results async This sample shows the use of WorkflowStub.getResult and WorkflowStub.getResultAsync -to show how the Temporal client api can not only start workflows async but also wait for their results +to show how the Temporal Client API can not only start Workflows async but also wait for their results async as well. ## Run the sample diff --git a/src/main/java/io/temporal/samples/listworkflows/README.md b/src/main/java/io/temporal/samples/listworkflows/README.md index ffa789334..4eb329695 100644 --- a/src/main/java/io/temporal/samples/listworkflows/README.md +++ b/src/main/java/io/temporal/samples/listworkflows/README.md @@ -1,9 +1,9 @@ # Demo List Workflows The sample demonstrates: -1) Setting custom search attributes for a workflow -2) Using ListWorkflowExecutionsRequest and use custom search attribute query to list -workflow executions that match that query +1) Setting custom search attributes for a Workflow +2) Using ListWorkflowExecutionsRequest and custom Search Attribute query to list +Workflow Executions that match that query ## Running diff --git a/src/main/java/io/temporal/samples/moneybatch/README.md b/src/main/java/io/temporal/samples/moneybatch/README.md index 18521ff77..701ef66c3 100644 --- a/src/main/java/io/temporal/samples/moneybatch/README.md +++ b/src/main/java/io/temporal/samples/moneybatch/README.md @@ -4,9 +4,9 @@ Demonstrates a situation when a single deposit should be initiated for multiple For example, a seller might want to be paid once per fixed number of transactions. The sample can be easily extended to perform a payment based on more complex criteria like a specific time or accumulated amount. -The sample also demonstrates the *signal with start* way of starting workflows. -If the workflow is already running, it just receives the signal. If it is not running, then it is started first, and then the signal is delivered to it. -You can think about *signal with start* as a lazy way to create workflows when signaling them. +The sample also demonstrates the *signal with start* way of starting Workflows. +If the Workflow is already running, it just receives the Signal. If it is not running, then it is started first, and then the signal is delivered to it. +You can think about *signal with start* as a lazy way to create Workflows when signaling them. **How to run the Money Batch Sample** diff --git a/src/main/java/io/temporal/samples/payloadconverter/crypto/README.md b/src/main/java/io/temporal/samples/payloadconverter/crypto/README.md index 8d7818149..fb2452667 100644 --- a/src/main/java/io/temporal/samples/payloadconverter/crypto/README.md +++ b/src/main/java/io/temporal/samples/payloadconverter/crypto/README.md @@ -1,7 +1,6 @@ # Custom Payload Converter (Crypto converter) -The sample demonstrates how you can override the default Json Converter -to encrypt/decrypt payloads using [jackson-json-crypto](https://github.com/codesqueak/jackson-json-crypto). +The sample demonstrates how you can override the default Json Converter to encrypt/decrypt payloads using [jackson-json-crypto](https://github.com/codesqueak/jackson-json-crypto). ## Running diff --git a/src/main/java/io/temporal/samples/peractivityoptions/README.md b/src/main/java/io/temporal/samples/peractivityoptions/README.md index 88db95a31..01aa850c9 100644 --- a/src/main/java/io/temporal/samples/peractivityoptions/README.md +++ b/src/main/java/io/temporal/samples/peractivityoptions/README.md @@ -1,6 +1,6 @@ # Per Activity Type Options Sample -This sample shows how to set per activity type options via +This sample shows how to set per Activity type options via WorkflowImplementationOptions ```bash diff --git a/src/main/java/io/temporal/samples/polling/frequent/README.md b/src/main/java/io/temporal/samples/polling/frequent/README.md index ab55e7ccb..e083c2729 100644 --- a/src/main/java/io/temporal/samples/polling/frequent/README.md +++ b/src/main/java/io/temporal/samples/polling/frequent/README.md @@ -1,6 +1,6 @@ ## Frequent polling -This sample shows how we can implement frequent polling (1 second or faster) inside our activity. +This sample shows how we can implement frequent polling (1 second or faster) inside our Activity. The implementation is a loop that polls our service and then sleeps for the poll interval (1 second in the sample). To ensure that polling activity is restarted in a timely manner, we make sure that it heartbeats on every iteration. diff --git a/src/main/java/io/temporal/samples/polling/infrequent/README.md b/src/main/java/io/temporal/samples/polling/infrequent/README.md index e720999aa..23cb672ba 100644 --- a/src/main/java/io/temporal/samples/polling/infrequent/README.md +++ b/src/main/java/io/temporal/samples/polling/infrequent/README.md @@ -1,26 +1,20 @@ ## Infrequent polling -This sample shows how we can use activity retries for infrequent polling of -a third-party service (for example via REST). +This sample shows how we can use Activity retries for infrequent polling of a third-party service (for example via REST). This method can be used for infrequent polls of one minute or slower. We utilize activity retries for this option, setting Retries options: * setBackoffCoefficient to 1 * setInitialInterval to the polling interval (in this sample set to 60 seconds) -This will allow us to retry our activity exactly on the set interval. +This will allow us to retry our Activity exactly on the set interval. To run this sample: ```bash ./gradlew -q execute -PmainClass=io.temporal.samples.polling.infrequent.Starter ``` -Since our test service simulates it being "down" for 4 polling attempts and then -returns "OK" on the 5th poll attempt, our workflow is going to perform -4 activity retries with a 60 second poll interval, and then return -the service result on the successful 5th attempt. +Since our test service simulates it being "down" for 4 polling attempts and then returns "OK" on the 5th poll attempt, our Workflow is going to perform 4 activity retries with a 60 second poll interval, and then return the service result on the successful 5th attempt. -Note that individual activity retries are not recorded in workflow history, -so we this approach we can poll for a very long time without -affecting the history size. +Note that individual Activity retries are not recorded in Workflow History, so we this approach we can poll for a very long time without affecting the history size. diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/README.md b/src/main/java/io/temporal/samples/polling/periodicsequence/README.md index 928c6be53..4e6acd5ba 100644 --- a/src/main/java/io/temporal/samples/polling/periodicsequence/README.md +++ b/src/main/java/io/temporal/samples/polling/periodicsequence/README.md @@ -1,11 +1,12 @@ ## Periodic sequence -This samples shows periodic polling via child workflow. Note this is a rare case scenario -where polling requires execution of a sequence of activities, or activity arguments need to change -between polling retries. -For this case we use a child workflow calls polling activities a set number of times in a loop and then periodically -calls continue as new. The parent workflow is not aware about the child workflow -calling continue as new and it gets notified when it completes (or fails). +This samples shows periodic polling via Child Workflow. + +This is a rare scenario where polling requires execution of a sequence of Activities, or Activity arguments need to change between polling retries. + +For this case we use a Child Workflow to call polling Activities a set number of times in a loop and then periodically calls continue-as-new. + +The Parent Workflow is not aware about the Child Workflow calling continue-as-new and it gets notified when it completes (or fails). To run this sample: ```bash diff --git a/src/main/java/io/temporal/samples/terminateworkflow/README.md b/src/main/java/io/temporal/samples/terminateworkflow/README.md index b52501986..54e78c9ff 100644 --- a/src/main/java/io/temporal/samples/terminateworkflow/README.md +++ b/src/main/java/io/temporal/samples/terminateworkflow/README.md @@ -1,7 +1,6 @@ # Terminate Workflow execution -The sample demonstrates shows how to terminate workflow execution -using the client API. +The sample demonstrates shows how to terminate Workflow Execution using the Client API. ```bash ./gradlew -q execute -PmainClass=io.temporal.samples.terminateworkflow.Starter From 595f32973ec69353496b388aa29339ec81a4636e Mon Sep 17 00:00:00 2001 From: Samantha Santiago Date: Fri, 6 Jan 2023 12:42:16 -0600 Subject: [PATCH 042/240] shortened links, updated legacy (#404) --- README.md | 90 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index a8e5c2462..3c6ae5002 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ enabled on the Temporal Server side. To do this you can run locally with: docker-compose -f docker-compose-cass-es.yml up Alternatively you could install the Temporal Server on Kubernetes / Minicube using the [Temporal Helm charts](https://github.com/temporalio/helm-charts). -Note that in this case you should use the [Temporal CLI (tctl)](https://docs.temporal.io/tctl-v1/) tool to create a namespace called "default": +Note that in this case you should use the [Temporal CLI (tctl)](https://docs.temporal.io/tctl-v1) tool to create a namespace called "default": tctl --ns default n re @@ -93,84 +93,84 @@ The following section lists all available samples. Click on the sample link to view the README, which contains instructions on how to run them. Each sample has an associated unit test which demonstrates the use of the Temporal Java SDK testing API. -All tests are available under [src/test/java](https://github.com/temporalio/samples-java/tree/main/src/test/java/io/temporal/samples) +All tests are available under [src/test/java](./src/test/java/io/temporal/samples) ### Hello samples -- [**Hello**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/hello): This sample includes a number of individual Workflows that can be executed independently. Each one demonstrates something specific. - - [**HelloActivity**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloActivity.java): Demonstrates a Workflow Definition that executes a single Activity. - - [**HelloActivityRetry**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java): Demonstrates how to Retry an Activity Execution. - - [**HelloActivityExclusiveChoice**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java): Demonstrates how to execute Activities based on dynamic input. - - [**HelloAsync**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloAsync.java): Demonstrates how to execute Activities asynchronously and wait for them using Promises. - - [**HelloParallelActivity**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java): Demonstrates how to execute multiple Activities in parallel, asynchronously, and wait for them using `Promise.allOf`. - - [**HelloAsyncActivityCompletion**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java): Demonstrates how to complete an Activity Execution asynchronously. - - [**HelloAsyncLambda**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java): Demonstrates how to execute part of a Workflow asynchronously in a separate task (thread). - - [**HelloCancellationScope**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java): Demonstrates how to explicitly cancel parts of a Workflow Execution. - - [**HelloDetachedCancellationScope**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java): Demonstrates how to execute cleanup code after a Workflow Execution has been explicitly cancelled. - - [**HelloChild**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloChild.java): Demonstrates how to execute a simple Child Workflow. - - [**HelloCron**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloCron.java): Demonstrates how to execute a Workflow according to a cron schedule. - - [**HelloDynamic**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloDynamic.java): Demonstrates how to use `DynamicWorkflow` and `DynamicActivity` interfaces. - - [**HelloPeriodic**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloPeriodic.java): Demonstrates the use of the Continue-As-New feature. - - [**HelloException**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloException.java): Demonstrates how to handle exception propagation and wrapping. - - [**HelloLocalActivity**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java): Demonstrates the use of a [Local Activity](https://docs.temporal.io/docs/jargon/mesh/#local-activity). - - [**HelloPolymorphicActivity**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java): Demonstrates Activity Definitions that extend a common interface. - - [**HelloQuery**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloQuery.java): Demonstrates how to Query the state of a Workflow Execution. - - [**HelloSignal**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloSignal.java): Demonstrates how to send and handle a Signal. - - [**HelloSaga**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloSaga.java): Demonstrates how to use the SAGA feature. - - [**HelloSearchAttributes**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java): Demonstrates how to add custom Search Attributes to Workflow Executions. - - [**HelloSideEffect**](https://github.com/temporalio/samples-java/blob/main/src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. +- [**Hello**](./src/main/java/io/temporal/samples/hello): This sample includes a number of individual Workflows that can be executed independently. Each one demonstrates something specific. + - [**HelloActivity**](./src/main/java/io/temporal/samples/hello/HelloActivity.java): Demonstrates a Workflow Definition that executes a single Activity. + - [**HelloActivityRetry**](./src/main/java/io/temporal/samples/hello/HelloActivityRetry.java): Demonstrates how to Retry an Activity Execution. + - [**HelloActivityExclusiveChoice**](./src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java): Demonstrates how to execute Activities based on dynamic input. + - [**HelloAsync**](./src/main/java/io/temporal/samples/hello/HelloAsync.java): Demonstrates how to execute Activities asynchronously and wait for them using Promises. + - [**HelloParallelActivity**](./src/main/java/io/temporal/samples/hello/HelloParallelActivity.java): Demonstrates how to execute multiple Activities in parallel, asynchronously, and wait for them using `Promise.allOf`. + - [**HelloAsyncActivityCompletion**](./src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java): Demonstrates how to complete an Activity Execution asynchronously. + - [**HelloAsyncLambda**](./src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java): Demonstrates how to execute part of a Workflow asynchronously in a separate task (thread). + - [**HelloCancellationScope**](./src/main/java/io/temporal/samples/hello/HelloCancellationScope.java): Demonstrates how to explicitly cancel parts of a Workflow Execution. + - [**HelloDetachedCancellationScope**](./src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java): Demonstrates how to execute cleanup code after a Workflow Execution has been explicitly cancelled. + - [**HelloChild**](./src/main/java/io/temporal/samples/hello/HelloChild.java): Demonstrates how to execute a simple Child Workflow. + - [**HelloCron**](./src/main/java/io/temporal/samples/hello/HelloCron.java): Demonstrates how to execute a Workflow according to a cron schedule. + - [**HelloDynamic**](./src/main/java/io/temporal/samples/hello/HelloDynamic.java): Demonstrates how to use `DynamicWorkflow` and `DynamicActivity` interfaces. + - [**HelloPeriodic**](./src/main/java/io/temporal/samples/hello/HelloPeriodic.java): Demonstrates the use of the Continue-As-New feature. + - [**HelloException**](./src/main/java/io/temporal/samples/hello/HelloException.java): Demonstrates how to handle exception propagation and wrapping. + - [**HelloLocalActivity**](./src/main/java/io/temporal/samples/hello/HelloLocalActivity.java): Demonstrates the use of a [Local Activity](https://docs.temporal.io/docs/jargon/mesh/#local-activity). + - [**HelloPolymorphicActivity**](./src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java): Demonstrates Activity Definitions that extend a common interface. + - [**HelloQuery**](./src/main/java/io/temporal/samples/hello/HelloQuery.java): Demonstrates how to Query the state of a Workflow Execution. + - [**HelloSignal**](./src/main/java/io/temporal/samples/hello/HelloSignal.java): Demonstrates how to send and handle a Signal. + - [**HelloSaga**](./src/main/java/io/temporal/samples/hello/HelloSaga.java): Demonstrates how to use the SAGA feature. + - [**HelloSearchAttributes**](./src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java): Demonstrates how to add custom Search Attributes to Workflow Executions. + - [**HelloSideEffect**](./src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. ### Scenario-based samples -- [**File Processing Sample**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/fileprocessing): Demonstrates how to route tasks to specific Workers. This sample has a set of Activities that download a file, processes it, and uploads the result to a destination. Any Worker can execute the first Activity. However, the second and third Activities must be executed on the same host as the first one. +- [**File Processing Sample**](./src/main/java/io/temporal/samples/fileprocessing): Demonstrates how to route tasks to specific Workers. This sample has a set of Activities that download a file, processes it, and uploads the result to a destination. Any Worker can execute the first Activity. However, the second and third Activities must be executed on the same host as the first one. -- [**Booking SAGA**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/bookingsaga): Demonstrates Temporals take on the Camunda BPMN "trip booking" example. +- [**Booking SAGA**](./src/main/java/io/temporal/samples/bookingsaga): Demonstrates Temporals take on the Camunda BPMN "trip booking" example. -- [**Money Transfer**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/moneytransfer): Demonstrates the use of a dedicated Activity Worker. +- [**Money Transfer**](./src/main/java/io/temporal/samples/moneytransfer): Demonstrates the use of a dedicated Activity Worker. -- [**Money Batch**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/moneybatch): Demonstrates a situation where a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. This sample can be easily extended to perform a payment based on more complex criteria, such as at a specific time or an accumulated amount. The sample also demonstrates how to Signal the Workflow when it executes (*Signal with start*). If the Workflow is already executing, it just receives the Signal. If it is not executing, then the Workflow executes first, and then the Signal is delivered to it. *Signal with start* is a "lazy" way to execute Workflows when Signaling them. +- [**Money Batch**](./src/main/java/io/temporal/samples/moneybatch): Demonstrates a situation where a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. This sample can be easily extended to perform a payment based on more complex criteria, such as at a specific time or an accumulated amount. The sample also demonstrates how to Signal the Workflow when it executes (*Signal with start*). If the Workflow is already executing, it just receives the Signal. If it is not executing, then the Workflow executes first, and then the Signal is delivered to it. *Signal with start* is a "lazy" way to execute Workflows when Signaling them. -- [**Customer Application Approval DSL**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/dsl): Demonstrates execution of a customer application approval workflow defined in a DSL (like JSON or YAML) +- [**Customer Application Approval DSL**](./src/main/java/io/temporal/samples/dsl): Demonstrates execution of a customer application approval workflow defined in a DSL (like JSON or YAML) -- [**Polling Services**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion +- [**Polling Services**](./src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion -- [**Heartbeating Activity Batch**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/batch/heartbeatingactivity): Batch job implementation using a heartbeating activity. +- [**Heartbeating Activity Batch**](./src/main/java/io/temporal/samples/batch/heartbeatingactivity): Batch job implementation using a heartbeating activity. -- [**Iterator Batch**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/batch/iterator): Batch job implementation using the workflow iterator pattern. +- [**Iterator Batch**](./src/main/java/io/temporal/samples/batch/iterator): Batch job implementation using the workflow iterator pattern. -- [**Sliding Window Batch**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. +- [**Sliding Window Batch**](./src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. ### API demonstrations -- [**Updatable Timer**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. +- [**Updatable Timer**](./src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. -- [**Workflow Interceptor**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/interceptor): Demonstrates how to create and register a simple Workflow Interceptor. +- [**Workflow Interceptor**](./src/main/java/io/temporal/samples/interceptor): Demonstrates how to create and register a simple Workflow Interceptor. -- [**List Workflows**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/listworkflows): Demonstrates the use of custom search attributes and ListWorkflowExecutionsRequest with custom queries. +- [**List Workflows**](./src/main/java/io/temporal/samples/listworkflows): Demonstrates the use of custom search attributes and ListWorkflowExecutionsRequest with custom queries. -- [**Payload Converter - CloudEvents**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/payloadconverter/cloudevents): Demonstrates the use of a custom payload converter for CloudEvents. +- [**Payload Converter - CloudEvents**](./src/main/java/io/temporal/samples/payloadconverter/cloudevents): Demonstrates the use of a custom payload converter for CloudEvents. -- [**Payload Converter - Crypto**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/payloadconverter/crypto): Demonstrates the use of a custom payload converter using jackson-json-crypto. +- [**Payload Converter - Crypto**](./src/main/java/io/temporal/samples/payloadconverter/crypto): Demonstrates the use of a custom payload converter using jackson-json-crypto. -- [**Async Child Workflow**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/asyncchild): Demonstrates how to invoke a child workflow async, that can complete after parent workflow is already completed. +- [**Async Child Workflow**](./src/main/java/io/temporal/samples/asyncchild): Demonstrates how to invoke a child workflow async, that can complete after parent workflow is already completed. -- [**Terminate Workflow**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/terminateworkflow): Demonstrates how to terminate a workflow using client API. +- [**Terminate Workflow**](./src/main/java/io/temporal/samples/terminateworkflow): Demonstrates how to terminate a workflow using client API. -- [**Get Workflow Results Async**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/getresultsasync): Demonstrates how to start and get workflow results in async manner. +- [**Get Workflow Results Async**](./src/main/java/io/temporal/samples/getresultsasync): Demonstrates how to start and get workflow results in async manner. -- [**Per Activity Type Options**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/peractivityoptions): Demonstrates how to set per Activity type options. +- [**Per Activity Type Options**](./src/main/java/io/temporal/samples/peractivityoptions): Demonstrates how to set per Activity type options. -- [**Configure WorkflowClient to use mTLS**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/ssl): Demonstrates how to configure WorkflowClient when using mTLS. +- [**Configure WorkflowClient to use mTLS**](./src/main/java/io/temporal/samples/ssl): Demonstrates how to configure WorkflowClient when using mTLS. ### SDK Metrics -- [**Set up SDK metrics**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics. +- [**Set up SDK metrics**](./src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics. ### Tracing Support -- [**Set up OpenTracing and/or OpenTelemetry with Jaeger**](https://github.com/temporalio/samples-java/tree/main/src/main/java/io/temporal/samples/tracing): Demonstrates how to set up OpenTracing and/or OpenTelemetry and view traces using Jaeger. +- [**Set up OpenTracing and/or OpenTelemetry with Jaeger**](./src/main/java/io/temporal/samples/tracing): Demonstrates how to set up OpenTracing and/or OpenTelemetry and view traces using Jaeger. From 277f09cd9c26ac1c653d479ac1ee64887f2abbd8 Mon Sep 17 00:00:00 2001 From: Edmondo Porcu Date: Fri, 13 Jan 2023 14:14:50 -0800 Subject: [PATCH 043/240] Fixing class references in README (#408) --- .../temporal/samples/polling/frequent/README.md | 2 +- .../InfrequentPollingWorkflowImpl.java | 16 +++++++++++----- .../samples/polling/infrequent/README.md | 2 +- .../samples/polling/periodicsequence/README.md | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/temporal/samples/polling/frequent/README.md b/src/main/java/io/temporal/samples/polling/frequent/README.md index e083c2729..b78689254 100644 --- a/src/main/java/io/temporal/samples/polling/frequent/README.md +++ b/src/main/java/io/temporal/samples/polling/frequent/README.md @@ -10,5 +10,5 @@ StartToClose timeout. To run this sample: ```bash -./gradlew -q execute -PmainClass=io.temporal.samples.polling.frequent.Starter +./gradlew -q execute -PmainClass=io.temporal.samples.polling.frequent.FrequentPollingStarter ``` \ No newline at end of file diff --git a/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java b/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java index 5c637c878..43f096e40 100644 --- a/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java @@ -31,11 +31,17 @@ public class InfrequentPollingWorkflowImpl implements PollingWorkflow { public String exec() { /** * Infrequent polling via activity can be implemented via activity retries. For this sample we - * want to poll the test service every 60 seconds. Here we: 1. Set RetryPolicy backoff - * coefficient of 1 2. Set initial interval to the poll frequency (since coefficient is 1, same - * interval will be used for all retries) With this in case our test service is "down" we can - * fail our activity and it will be retried based on our 60 second retry interval until poll is - * successful and we can return a result from the activity. + * want to poll the test service every 60 seconds. Here we: + * + *

    + *
  1. Set RetryPolicy backoff coefficient of 1 + *
  2. Set initial interval to the poll frequency (since coefficient is 1, same interval will + * be used for all retries) + *
+ * + *

With this in case our test service is "down" we can fail our activity and it will be + * retried based on our 60 second retry interval until poll is successful and we can return a + * result from the activity. */ ActivityOptions options = ActivityOptions.newBuilder() diff --git a/src/main/java/io/temporal/samples/polling/infrequent/README.md b/src/main/java/io/temporal/samples/polling/infrequent/README.md index 23cb672ba..f227db6ca 100644 --- a/src/main/java/io/temporal/samples/polling/infrequent/README.md +++ b/src/main/java/io/temporal/samples/polling/infrequent/README.md @@ -11,7 +11,7 @@ This will allow us to retry our Activity exactly on the set interval. To run this sample: ```bash -./gradlew -q execute -PmainClass=io.temporal.samples.polling.infrequent.Starter +./gradlew -q execute -PmainClass=io.temporal.samples.polling.infrequent.InfrequentPollingStarter ``` Since our test service simulates it being "down" for 4 polling attempts and then returns "OK" on the 5th poll attempt, our Workflow is going to perform 4 activity retries with a 60 second poll interval, and then return the service result on the successful 5th attempt. diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/README.md b/src/main/java/io/temporal/samples/polling/periodicsequence/README.md index 4e6acd5ba..0a743ce6a 100644 --- a/src/main/java/io/temporal/samples/polling/periodicsequence/README.md +++ b/src/main/java/io/temporal/samples/polling/periodicsequence/README.md @@ -10,5 +10,5 @@ The Parent Workflow is not aware about the Child Workflow calling continue-as-ne To run this sample: ```bash -./gradlew -q execute -PmainClass=io.temporal.samples.polling.periodicsequene.Starter +./gradlew -q execute -PmainClass=io.temporal.samples.polling.periodicsequence.PeriodicPollingStarter ``` From ff36cb7c90bace114e608265be988ab00cd5fce8 Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Sat, 21 Jan 2023 13:52:11 -0800 Subject: [PATCH 044/240] Retry activity on signal interceptor (#413) Demonstrates how to create and register an interceptor that retries an activity on a signal. --- README.md | 4 +- .../ClientCounter.java | 2 +- .../InterceptorStarter.java | 10 +- .../README.md | 2 +- .../SimpleClientCallsInterceptor.java | 2 +- .../SimpleClientInterceptor.java | 2 +- ...eCountActivityInboundCallsInterceptor.java | 2 +- .../SimpleCountWorkerInterceptor.java | 2 +- ...eCountWorkflowInboundCallsInterceptor.java | 2 +- ...CountWorkflowOutboundCallsInterceptor.java | 2 +- .../WorkerCounter.java | 2 +- .../activities/MyActivities.java | 2 +- .../activities/MyActivitiesImpl.java | 2 +- .../workflow/MyChildWorkflow.java | 2 +- .../workflow/MyChildWorkflowImpl.java | 4 +- .../workflow/MyWorkflow.java | 2 +- .../workflow/MyWorkflowImpl.java | 2 +- .../FailureRequester.java | 47 +++++ .../retryonsignalinterceptor/MyActivity.java | 27 +++ .../MyActivityImpl.java | 45 +++++ .../retryonsignalinterceptor/MyWorkflow.java | 30 ++++ .../MyWorkflowImpl.java | 43 +++++ .../MyWorkflowWorker.java | 64 +++++++ .../QueryRequester.java | 44 +++++ .../retryonsignalinterceptor/README.MD | 22 +++ .../RetryOnSignalInterceptorListener.java | 39 ++++ .../RetryOnSignalWorkerInterceptor.java | 37 ++++ ...SignalWorkflowInboundCallsInterceptor.java | 37 ++++ ...ignalWorkflowOutboundCallsInterceptor.java | 170 ++++++++++++++++++ .../RetryRequester.java | 44 +++++ .../ClientCountInterceptorTest.java | 10 +- .../WorkerCountInterceptorTest.java | 10 +- .../RetryOnSignalInterceptorTest.java | 120 +++++++++++++ 33 files changed, 803 insertions(+), 32 deletions(-) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/ClientCounter.java (98%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/InterceptorStarter.java (91%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/README.md (84%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/SimpleClientCallsInterceptor.java (97%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/SimpleClientInterceptor.java (96%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/SimpleCountActivityInboundCallsInterceptor.java (97%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/SimpleCountWorkerInterceptor.java (96%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/SimpleCountWorkflowInboundCallsInterceptor.java (97%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/SimpleCountWorkflowOutboundCallsInterceptor.java (96%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/WorkerCounter.java (98%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/activities/MyActivities.java (94%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/activities/MyActivitiesImpl.java (94%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/workflow/MyChildWorkflow.java (94%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/workflow/MyChildWorkflowImpl.java (91%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/workflow/MyWorkflow.java (95%) rename src/main/java/io/temporal/samples/{interceptor => countinterceptor}/workflow/MyWorkflowImpl.java (97%) create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java create mode 100644 src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java rename src/test/java/io/temporal/samples/{interceptor => countinterceptor}/ClientCountInterceptorTest.java (90%) rename src/test/java/io/temporal/samples/{interceptor => countinterceptor}/WorkerCountInterceptorTest.java (90%) create mode 100644 src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java diff --git a/README.md b/README.md index 3c6ae5002..6393d2cf4 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,9 @@ All tests are available under [src/test/java](./src/test/java/io/temporal/sample - [**Updatable Timer**](./src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. -- [**Workflow Interceptor**](./src/main/java/io/temporal/samples/interceptor): Demonstrates how to create and register a simple Workflow Interceptor. +- [**Workflow Count Interceptor**](./src/main/java/io/temporal/samples/countinterceptor): Demonstrates how to create and register a simple Workflow Count Interceptor. +- +- [**Workflow Retry On Signal Interceptor**](./src/main/java/io/temporal/samples/retryonsignalinterceptor): Demonstrates how to create and register an interceptor that retries an activity on a signal. - [**List Workflows**](./src/main/java/io/temporal/samples/listworkflows): Demonstrates the use of custom search attributes and ListWorkflowExecutionsRequest with custom queries. diff --git a/src/main/java/io/temporal/samples/interceptor/ClientCounter.java b/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java similarity index 98% rename from src/main/java/io/temporal/samples/interceptor/ClientCounter.java rename to src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java index 9a80d08cf..d0bbf7f3b 100644 --- a/src/main/java/io/temporal/samples/interceptor/ClientCounter.java +++ b/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import java.util.AbstractMap; import java.util.Collections; diff --git a/src/main/java/io/temporal/samples/interceptor/InterceptorStarter.java b/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java similarity index 91% rename from src/main/java/io/temporal/samples/interceptor/InterceptorStarter.java rename to src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java index 4ebb0b7df..c3c8280c7 100644 --- a/src/main/java/io/temporal/samples/interceptor/InterceptorStarter.java +++ b/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java @@ -17,17 +17,17 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.common.interceptors.WorkflowClientInterceptor; -import io.temporal.samples.interceptor.activities.MyActivitiesImpl; -import io.temporal.samples.interceptor.workflow.MyChildWorkflowImpl; -import io.temporal.samples.interceptor.workflow.MyWorkflow; -import io.temporal.samples.interceptor.workflow.MyWorkflowImpl; +import io.temporal.samples.countinterceptor.activities.MyActivitiesImpl; +import io.temporal.samples.countinterceptor.workflow.MyChildWorkflowImpl; +import io.temporal.samples.countinterceptor.workflow.MyWorkflow; +import io.temporal.samples.countinterceptor.workflow.MyWorkflowImpl; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; diff --git a/src/main/java/io/temporal/samples/interceptor/README.md b/src/main/java/io/temporal/samples/countinterceptor/README.md similarity index 84% rename from src/main/java/io/temporal/samples/interceptor/README.md rename to src/main/java/io/temporal/samples/countinterceptor/README.md index 1c5860b95..62da81e15 100644 --- a/src/main/java/io/temporal/samples/interceptor/README.md +++ b/src/main/java/io/temporal/samples/countinterceptor/README.md @@ -7,5 +7,5 @@ The sample demonstrates: Run the following command to start the sample: ```bash -./gradlew -q execute -PmainClass=io.temporal.samples.interceptor.InterceptorStarter +./gradlew -q execute -PmainClass=io.temporal.samples.countinterceptor.InterceptorStarter ``` diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleClientCallsInterceptor.java b/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java similarity index 97% rename from src/main/java/io/temporal/samples/interceptor/SimpleClientCallsInterceptor.java rename to src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java index 1b5a40973..c6deda735 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleClientCallsInterceptor.java +++ b/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.WorkflowClientCallsInterceptor; import io.temporal.common.interceptors.WorkflowClientCallsInterceptorBase; diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleClientInterceptor.java b/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java similarity index 96% rename from src/main/java/io/temporal/samples/interceptor/SimpleClientInterceptor.java rename to src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java index bfdec3a47..aafc7625c 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleClientInterceptor.java +++ b/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.WorkflowClientCallsInterceptor; import io.temporal.common.interceptors.WorkflowClientInterceptorBase; diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleCountActivityInboundCallsInterceptor.java b/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java similarity index 97% rename from src/main/java/io/temporal/samples/interceptor/SimpleCountActivityInboundCallsInterceptor.java rename to src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java index 5e340da92..a866680ff 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleCountActivityInboundCallsInterceptor.java +++ b/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import io.temporal.activity.ActivityExecutionContext; import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkerInterceptor.java b/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java similarity index 96% rename from src/main/java/io/temporal/samples/interceptor/SimpleCountWorkerInterceptor.java rename to src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java index 1fa8f3311..268d2620a 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkerInterceptor.java +++ b/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; import io.temporal.common.interceptors.WorkerInterceptor; diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowInboundCallsInterceptor.java b/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java similarity index 97% rename from src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowInboundCallsInterceptor.java rename to src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java index c1c6db29c..8acd6d177 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowInboundCallsInterceptor.java +++ b/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; import io.temporal.common.interceptors.WorkflowInboundCallsInterceptorBase; diff --git a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowOutboundCallsInterceptor.java b/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java similarity index 96% rename from src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowOutboundCallsInterceptor.java rename to src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java index 0b2997109..1add50445 100644 --- a/src/main/java/io/temporal/samples/interceptor/SimpleCountWorkflowOutboundCallsInterceptor.java +++ b/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptorBase; diff --git a/src/main/java/io/temporal/samples/interceptor/WorkerCounter.java b/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java similarity index 98% rename from src/main/java/io/temporal/samples/interceptor/WorkerCounter.java rename to src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java index 86e01cc4b..d6d35abfd 100644 --- a/src/main/java/io/temporal/samples/interceptor/WorkerCounter.java +++ b/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import java.util.AbstractMap; import java.util.Collections; diff --git a/src/main/java/io/temporal/samples/interceptor/activities/MyActivities.java b/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java similarity index 94% rename from src/main/java/io/temporal/samples/interceptor/activities/MyActivities.java rename to src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java index 85ca1a8b8..5935003e9 100644 --- a/src/main/java/io/temporal/samples/interceptor/activities/MyActivities.java +++ b/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor.activities; +package io.temporal.samples.countinterceptor.activities; import io.temporal.activity.ActivityInterface; diff --git a/src/main/java/io/temporal/samples/interceptor/activities/MyActivitiesImpl.java b/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java similarity index 94% rename from src/main/java/io/temporal/samples/interceptor/activities/MyActivitiesImpl.java rename to src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java index c40ea08a7..b2ca5edf2 100644 --- a/src/main/java/io/temporal/samples/interceptor/activities/MyActivitiesImpl.java +++ b/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor.activities; +package io.temporal.samples.countinterceptor.activities; public class MyActivitiesImpl implements MyActivities { @Override diff --git a/src/main/java/io/temporal/samples/interceptor/workflow/MyChildWorkflow.java b/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java similarity index 94% rename from src/main/java/io/temporal/samples/interceptor/workflow/MyChildWorkflow.java rename to src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java index 24a568bd6..36e5099da 100644 --- a/src/main/java/io/temporal/samples/interceptor/workflow/MyChildWorkflow.java +++ b/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor.workflow; +package io.temporal.samples.countinterceptor.workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; diff --git a/src/main/java/io/temporal/samples/interceptor/workflow/MyChildWorkflowImpl.java b/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java similarity index 91% rename from src/main/java/io/temporal/samples/interceptor/workflow/MyChildWorkflowImpl.java rename to src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java index cdca2f63f..d4a944071 100644 --- a/src/main/java/io/temporal/samples/interceptor/workflow/MyChildWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java @@ -17,10 +17,10 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor.workflow; +package io.temporal.samples.countinterceptor.workflow; import io.temporal.activity.ActivityOptions; -import io.temporal.samples.interceptor.activities.MyActivities; +import io.temporal.samples.countinterceptor.activities.MyActivities; import io.temporal.workflow.Workflow; import java.time.Duration; diff --git a/src/main/java/io/temporal/samples/interceptor/workflow/MyWorkflow.java b/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java similarity index 95% rename from src/main/java/io/temporal/samples/interceptor/workflow/MyWorkflow.java rename to src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java index 5f1581052..8541fc604 100644 --- a/src/main/java/io/temporal/samples/interceptor/workflow/MyWorkflow.java +++ b/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor.workflow; +package io.temporal.samples.countinterceptor.workflow; import io.temporal.workflow.QueryMethod; import io.temporal.workflow.SignalMethod; diff --git a/src/main/java/io/temporal/samples/interceptor/workflow/MyWorkflowImpl.java b/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java similarity index 97% rename from src/main/java/io/temporal/samples/interceptor/workflow/MyWorkflowImpl.java rename to src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java index ff578ef4c..f20876e16 100644 --- a/src/main/java/io/temporal/samples/interceptor/workflow/MyWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor.workflow; +package io.temporal.samples.countinterceptor.workflow; import io.temporal.workflow.ChildWorkflowOptions; import io.temporal.workflow.Workflow; diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java new file mode 100644 index 000000000..78bc3b7c7 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; + +/** + * Send signal requesting that an exception thrown from the activity is propagated to the workflow. + */ +public class FailureRequester { + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + // Note that we use the listener interface that the interceptor registered dynamically, not the + // workflow interface. + RetryOnSignalInterceptorListener workflow = + client.newWorkflowStub(RetryOnSignalInterceptorListener.class, WORKFLOW_ID); + + // Sends "Fail" signal to the workflow. + workflow.fail(); + + System.out.println("\"Fail\" signal sent"); + System.exit(0); + } +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java new file mode 100644 index 000000000..515d93b33 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface MyActivity { + void execute(); +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java new file mode 100644 index 000000000..2e120c353 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import io.temporal.failure.ApplicationFailure; +import java.util.concurrent.atomic.AtomicInteger; + +public class MyActivityImpl implements MyActivity { + + /** + * WARNING! Never rely on such shared state in real applications. The activity variables are per + * process and in almost all cases multiple worker processes are used. + */ + private final AtomicInteger count = new AtomicInteger(); + + /** Sleeps 5 seconds. Fails for 4 first invocations, and then completes. */ + @Override + public void execute() { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + if (count.incrementAndGet() < 5) { + throw ApplicationFailure.newFailure("simulated", "type1"); + } + } +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java new file mode 100644 index 000000000..b9449b3c0 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface MyWorkflow { + + @WorkflowMethod + void execute(); +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java new file mode 100644 index 000000000..b12ee8307 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.RetryOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class MyWorkflowImpl implements MyWorkflow { + + private final MyActivity activity = + Workflow.newActivityStub( + MyActivity.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(30)) + // disable server side retries. In most production applications the retries should be + // done for a while before requiring an external operator signal. + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) + .build()); + + @Override + public void execute() { + activity.execute(); + } +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java new file mode 100644 index 000000000..f191ba1ad --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerFactoryOptions; + +public class MyWorkflowWorker { + + static final String TASK_QUEUE = "RetryOnSignalInterceptor"; + static final String WORKFLOW_ID = "RetryOnSignalInterceptor1"; + + public static void main(String[] args) { + + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + // Register interceptor with the factory. + WorkerFactoryOptions factoryOptions = + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors(new RetryOnSignalWorkerInterceptor()) + .validateAndBuildWithDefaults(); + WorkerFactory factory = WorkerFactory.newInstance(client, factoryOptions); + Worker worker = factory.newWorker(TASK_QUEUE); + worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); + worker.registerActivitiesImplementations(new MyActivityImpl()); + factory.start(); + + // Create the workflow client stub. It is used to start our workflow execution. + MyWorkflow workflow = + client.newWorkflowStub( + MyWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + // Execute workflow waiting for it to complete. + System.out.println("Starting workflow " + WORKFLOW_ID); + workflow.execute(); + System.out.println("Workflow completed"); + System.exit(0); + } +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java new file mode 100644 index 000000000..06adda488 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; + +public class QueryRequester { + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + // Note that we use the listener interface that the interceptor registered dynamically, not the + // workflow interface. + RetryOnSignalInterceptorListener workflow = + client.newWorkflowStub(RetryOnSignalInterceptorListener.class, WORKFLOW_ID); + + // Queries workflow. + String status = workflow.getPendingActivitiesStatus(); + + System.out.println("Workflow Pending Activities Status:\n\n" + status); + System.exit(0); + } +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD b/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD new file mode 100644 index 000000000..ab46ac1df --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD @@ -0,0 +1,22 @@ +# The Retry On Signal Interceptor + +Demonstrates an interceptor that upon activity failure waits for an external signal that indicates if activity should +fail or retry. + +Starts Worker. The worker upon start initiates a workflow that has an activity that fails on the fist invocation. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.Worker +``` + +Sends Signal to indicate that the activity should be retried. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.RetryActivity +``` + +Sends a signal to propagate the activity failure to the workflow instead of retrying. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.FailActivity +``` diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java new file mode 100644 index 000000000..8b56cd0cd --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import io.temporal.workflow.QueryMethod; +import io.temporal.workflow.SignalMethod; + +/** Interface used to dynamically register signal and query handlers from the interceptor. */ +public interface RetryOnSignalInterceptorListener { + + /** Requests retry of the activities waiting after failure. */ + @SignalMethod + void retry(); + + /** Requests no more retries of the activities waiting after failure. */ + @SignalMethod + void fail(); + + /** Returns human status of the pending activities. */ + @QueryMethod + String getPendingActivitiesStatus(); +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java new file mode 100644 index 000000000..6e4ba7db0 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; +import io.temporal.common.interceptors.WorkerInterceptor; +import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; + +/** Should be registered through WorkerFactoryOptions. */ +public class RetryOnSignalWorkerInterceptor implements WorkerInterceptor { + @Override + public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) { + return new RetryOnSignalWorkflowInboundCallsInterceptor(next); + } + + @Override + public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) { + return next; + } +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java new file mode 100644 index 000000000..7b62aee9f --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; +import io.temporal.common.interceptors.WorkflowInboundCallsInterceptorBase; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; + +public class RetryOnSignalWorkflowInboundCallsInterceptor + extends WorkflowInboundCallsInterceptorBase { + + public RetryOnSignalWorkflowInboundCallsInterceptor(WorkflowInboundCallsInterceptor next) { + super(next); + } + + @Override + public void init(WorkflowOutboundCallsInterceptor outboundCalls) { + super.init(new RetryOnSignalWorkflowOutboundCallsInterceptor(outboundCalls)); + } +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java new file mode 100644 index 000000000..7c33c96d6 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import com.google.common.base.Throwables; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptorBase; +import io.temporal.workflow.*; +import java.util.ArrayList; +import java.util.List; + +/** + * Most of the complexity of the implementation is due to the asynchronous nature of the activity + * invocation at the interceptor level. + */ +public class RetryOnSignalWorkflowOutboundCallsInterceptor + extends WorkflowOutboundCallsInterceptorBase { + + private enum Action { + RETRY, + FAIL + } + + private class ActivityRetryState { + private final ActivityInput input; + private final CompletablePromise asyncResult = Workflow.newPromise(); + private CompletablePromise action; + private Exception lastFailure; + private int attempt; + + private ActivityRetryState(ActivityInput input) { + this.input = input; + } + + ActivityOutput execute() { + executeWithAsyncRetry(); + return new ActivityOutput<>(asyncResult); + } + + // Executes activity with retry based on signaled action asynchronously + private void executeWithAsyncRetry() { + attempt++; + lastFailure = null; + action = null; + ActivityOutput result = + RetryOnSignalWorkflowOutboundCallsInterceptor.super.executeActivity(input); + result + .getResult() + .handle( + (r, failure) -> { + // No failure complete + if (failure == null) { + pendingActivities.remove(this); + asyncResult.complete(r); + return null; + } + // Asynchronously executes requested action when signal is received. + lastFailure = failure; + action = Workflow.newPromise(); + return action.thenApply( + a -> { + if (a == Action.FAIL) { + asyncResult.completeExceptionally(failure); + } else { + // Retries recursively. + executeWithAsyncRetry(); + } + return null; + }); + }); + } + + public void retry() { + if (action == null) { + return; + } + action.complete(Action.RETRY); + } + + public void fail() { + if (action == null) { + return; + } + action.complete(Action.FAIL); + } + + public String getStatus() { + String activityName = input.getActivityName(); + if (lastFailure == null) { + return "Executing activity \"" + activityName + "\". Attempt=" + attempt; + } + if (!action.isCompleted()) { + return "Last \"" + + activityName + + "\" activity failure:\n" + + Throwables.getStackTraceAsString(lastFailure) + + "\n\nretry or fail ?"; + } + return (action.get() == Action.RETRY ? "Going to retry" : "Going to fail") + + " activity \"" + + activityName + + "\""; + } + } + + /** + * For the example brevity the interceptor fails or retries all activities that are waiting for an + * action. The production version might implement retry and failure of specific activities by + * their type. + */ + private final List> pendingActivities = new ArrayList<>(); + + public RetryOnSignalWorkflowOutboundCallsInterceptor(WorkflowOutboundCallsInterceptor next) { + super(next); + // Registers the listener for retry and fail signals as well as getPendingActivitiesStatus + // query. Register in the constructor to do it once per workflow instance. + Workflow.registerListener( + new RetryOnSignalInterceptorListener() { + @Override + public void retry() { + for (ActivityRetryState pending : pendingActivities) { + pending.retry(); + } + } + + @Override + public void fail() { + for (ActivityRetryState pending : pendingActivities) { + pending.fail(); + } + } + + @Override + public String getPendingActivitiesStatus() { + StringBuilder result = new StringBuilder(); + for (ActivityRetryState pending : pendingActivities) { + if (result.length() > 0) { + result.append('\n'); + } + result.append(pending.getStatus()); + } + return result.toString(); + } + }); + } + + @Override + public ActivityOutput executeActivity(ActivityInput input) { + ActivityRetryState retryState = new ActivityRetryState(input); + pendingActivities.add(retryState); + return retryState.execute(); + } +} diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java new file mode 100644 index 000000000..f5113d3a4 --- /dev/null +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; + +public class RetryRequester { + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + // Note that we use the listener interface that the interceptor registered dynamically, not the + // workflow interface. + RetryOnSignalInterceptorListener workflow = + client.newWorkflowStub(RetryOnSignalInterceptorListener.class, WORKFLOW_ID); + + // Sends "Retry" signal to the workflow. + workflow.retry(); + + System.out.println("\"Retry\" signal sent"); + System.exit(0); + } +} diff --git a/src/test/java/io/temporal/samples/interceptor/ClientCountInterceptorTest.java b/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java similarity index 90% rename from src/test/java/io/temporal/samples/interceptor/ClientCountInterceptorTest.java rename to src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java index c6f9a6baf..4ec530a4c 100644 --- a/src/test/java/io/temporal/samples/interceptor/ClientCountInterceptorTest.java +++ b/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -26,10 +26,10 @@ import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; -import io.temporal.samples.interceptor.activities.MyActivitiesImpl; -import io.temporal.samples.interceptor.workflow.MyChildWorkflowImpl; -import io.temporal.samples.interceptor.workflow.MyWorkflow; -import io.temporal.samples.interceptor.workflow.MyWorkflowImpl; +import io.temporal.samples.countinterceptor.activities.MyActivitiesImpl; +import io.temporal.samples.countinterceptor.workflow.MyChildWorkflowImpl; +import io.temporal.samples.countinterceptor.workflow.MyWorkflow; +import io.temporal.samples.countinterceptor.workflow.MyWorkflowImpl; import io.temporal.testing.TestWorkflowRule; import org.junit.Rule; import org.junit.Test; diff --git a/src/test/java/io/temporal/samples/interceptor/WorkerCountInterceptorTest.java b/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java similarity index 90% rename from src/test/java/io/temporal/samples/interceptor/WorkerCountInterceptorTest.java rename to src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java index c242d8bd3..4ec0f90d4 100644 --- a/src/test/java/io/temporal/samples/interceptor/WorkerCountInterceptorTest.java +++ b/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java @@ -17,17 +17,17 @@ * permissions and limitations under the License. */ -package io.temporal.samples.interceptor; +package io.temporal.samples.countinterceptor; import static org.junit.Assert.*; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; -import io.temporal.samples.interceptor.activities.MyActivitiesImpl; -import io.temporal.samples.interceptor.workflow.MyChildWorkflowImpl; -import io.temporal.samples.interceptor.workflow.MyWorkflow; -import io.temporal.samples.interceptor.workflow.MyWorkflowImpl; +import io.temporal.samples.countinterceptor.activities.MyActivitiesImpl; +import io.temporal.samples.countinterceptor.workflow.MyChildWorkflowImpl; +import io.temporal.samples.countinterceptor.workflow.MyWorkflow; +import io.temporal.samples.countinterceptor.workflow.MyWorkflowImpl; import io.temporal.testing.TestWorkflowRule; import io.temporal.worker.WorkerFactoryOptions; import org.junit.Rule; diff --git a/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java b/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java new file mode 100644 index 000000000..1e7696194 --- /dev/null +++ b/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.retryonsignalinterceptor; + +import static org.junit.Assert.*; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.ApplicationFailure; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowRule; +import io.temporal.worker.WorkerFactoryOptions; +import java.time.Duration; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Rule; +import org.junit.Test; + +public class RetryOnSignalInterceptorTest { + + static class TestActivityImpl implements MyActivity { + + final AtomicInteger count = new AtomicInteger(); + + @Override + public void execute() { + if (count.incrementAndGet() < 5) { + throw ApplicationFailure.newFailure("simulated", "type1"); + } + } + } + + private final TestActivityImpl testActivity = new TestActivityImpl(); + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors(new RetryOnSignalWorkerInterceptor()) + .validateAndBuildWithDefaults()) + .setWorkflowTypes(MyWorkflowImpl.class) + .setActivityImplementations(testActivity) + .build(); + + @Test + public void testRetryThenFail() { + testActivity.count.set(0); + TestWorkflowEnvironment testEnvironment = testWorkflowRule.getTestEnvironment(); + MyWorkflow workflow = testWorkflowRule.newWorkflowStub(MyWorkflow.class); + WorkflowExecution execution = WorkflowClient.start(workflow::execute); + + // Get stub to the dynamically registered interface + RetryOnSignalInterceptorListener listener = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(RetryOnSignalInterceptorListener.class, execution.getWorkflowId()); + testEnvironment.sleep(Duration.ofMinutes(10)); + listener.retry(); + testEnvironment.sleep(Duration.ofMinutes(10)); + listener.retry(); + testEnvironment.sleep(Duration.ofMinutes(10)); + listener.retry(); + testEnvironment.sleep(Duration.ofMinutes(10)); + listener.fail(); + WorkflowStub untyped = + testWorkflowRule.getWorkflowClient().newUntypedWorkflowStub(execution.getWorkflowId()); + try { + untyped.getResult(Void.class); + fail("unreachable"); + } catch (Exception e) { + assertTrue(e.getCause() instanceof ActivityFailure); + assertTrue(e.getCause().getCause() instanceof ApplicationFailure); + assertEquals( + "message='simulated', type='type1', nonRetryable=false", + e.getCause().getCause().getMessage()); + } + assertEquals(4, testActivity.count.get()); + } + + @Test + public void testRetryUntilSucceeds() { + testActivity.count.set(0); + TestWorkflowEnvironment testEnvironment = testWorkflowRule.getTestEnvironment(); + MyWorkflow workflow = testWorkflowRule.newWorkflowStub(MyWorkflow.class); + WorkflowExecution execution = WorkflowClient.start(workflow::execute); + + // Get stub to the dynamically registered interface + RetryOnSignalInterceptorListener listener = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(RetryOnSignalInterceptorListener.class, execution.getWorkflowId()); + for (int i = 0; i < 4; i++) { + testEnvironment.sleep(Duration.ofMinutes(10)); + listener.retry(); + } + WorkflowStub untyped = + testWorkflowRule.getWorkflowClient().newUntypedWorkflowStub(execution.getWorkflowId()); + untyped.getResult(Void.class); + assertEquals(5, testActivity.count.get()); + } +} From 53b155a660078538a376f0d5a08c934d4a7450bf Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Tue, 31 Jan 2023 13:26:28 -0500 Subject: [PATCH 045/240] Upgrade to JavaSDK 1.18.0 (#415) --- build.gradle | 12 ++++++++---- ...etryOnSignalWorkflowOutboundCallsInterceptor.java | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index f5870e6ef..615cb68d9 100644 --- a/build.gradle +++ b/build.gradle @@ -20,13 +20,17 @@ repositories { mavenCentral() } +ext { + javaSDKVersion = '1.18.0' +} + dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.1")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.21.0")) implementation(platform("org.junit:junit-bom:5.9.1")) - implementation "io.temporal:temporal-sdk:1.17.0" - implementation "io.temporal:temporal-opentracing:1.17.0" + implementation "io.temporal:temporal-sdk:$javaSDKVersion" + implementation "io.temporal:temporal-opentracing:$javaSDKVersion" implementation "com.fasterxml.jackson.core:jackson-databind" implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' @@ -54,10 +58,10 @@ dependencies { // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' - testImplementation("io.temporal:temporal-testing:1.17.0") + testImplementation("io.temporal:temporal-testing:$javaSDKVersion") testImplementation "junit:junit:4.13.2" - testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.11.0' + testImplementation "org.mockito:mockito-core:5.1.0" testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' testImplementation "org.junit.jupiter:junit-jupiter-api" diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java index 7c33c96d6..a7ac7e33c 100644 --- a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java +++ b/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java @@ -50,12 +50,11 @@ private ActivityRetryState(ActivityInput input) { } ActivityOutput execute() { - executeWithAsyncRetry(); - return new ActivityOutput<>(asyncResult); + return executeWithAsyncRetry(); } // Executes activity with retry based on signaled action asynchronously - private void executeWithAsyncRetry() { + private ActivityOutput executeWithAsyncRetry() { attempt++; lastFailure = null; action = null; @@ -85,6 +84,7 @@ private void executeWithAsyncRetry() { return null; }); }); + return new ActivityOutput<>(result.getActivityId(), asyncResult); } public void retry() { From c1ca2efb3bc26d955a1b3847353166f732302fc2 Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Thu, 2 Feb 2023 16:37:16 -0500 Subject: [PATCH 046/240] Upgrade to java-sdk 1.18.0 (#417) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 615cb68d9..0a8ac9819 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ repositories { } ext { - javaSDKVersion = '1.18.0' + javaSDKVersion = '1.18.1' } dependencies { From 378c0a661b893efef035faab9c86b76d4736ae81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:59:16 -0500 Subject: [PATCH 047/240] Bump opentelemetry-bom from 1.21.0 to 1.22.0 (#405) Bumps [opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.21.0 to 1.22.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.21.0...v1.22.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0a8ac9819..eb70e0b4d 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ ext { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.1")) - implementation(platform("io.opentelemetry:opentelemetry-bom:1.21.0")) + implementation(platform("io.opentelemetry:opentelemetry-bom:1.22.0")) implementation(platform("org.junit:junit-bom:5.9.1")) implementation "io.temporal:temporal-sdk:$javaSDKVersion" From a40219de652164f5cc26a2f268912133d91f59af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:00:29 -0500 Subject: [PATCH 048/240] Bump error_prone_core from 2.17.0 to 2.18.0 (#409) Bumps [error_prone_core](https://github.com/google/error-prone) from 2.17.0 to 2.18.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.17.0...v2.18.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index eb70e0b4d..4922f2480 100644 --- a/build.gradle +++ b/build.gradle @@ -71,9 +71,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.17.0') + errorprone('com.google.errorprone:error_prone_core:2.18.0') } else { - errorprone('com.google.errorprone:error_prone_core:2.17.0') + errorprone('com.google.errorprone:error_prone_core:2.18.0') } } } From 1c90a3118bb87e782218599a6d6534363bd90743 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:01:51 -0500 Subject: [PATCH 049/240] Bump org.mockito:mockito-core from 5.1.0 to 5.1.1 (#416) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.1.0 to 5.1.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.1.0...v5.1.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4922f2480..b435118ea 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:$javaSDKVersion") testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.1.0" + testImplementation "org.mockito:mockito-core:5.1.1" testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' testImplementation "org.junit.jupiter:junit-jupiter-api" From b1dcffd3affb97452eedc967d59a1070acdf91bf Mon Sep 17 00:00:00 2001 From: Edmondo Porcu Date: Mon, 6 Feb 2023 09:26:13 -0800 Subject: [PATCH 050/240] Backporting requirement for higher start to close timeout (#411) --- .../samples/polling/frequent/FrequentPollingWorkflowImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java b/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java index 4afc803dd..b4d8cfe70 100644 --- a/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java @@ -37,7 +37,7 @@ public String exec() { ActivityOptions options = ActivityOptions.newBuilder() // Set activity StartToClose timeout (single activity exec), does not include retries - .setStartToCloseTimeout(Duration.ofSeconds(10)) + .setStartToCloseTimeout(Duration.ofSeconds(60)) .setHeartbeatTimeout(Duration.ofSeconds(2)) // For sample we just use the default retry policy (do not set explicitly) .build(); From d0de96de13b3376dff3a74fd93a33c6019b46956 Mon Sep 17 00:00:00 2001 From: Edmondo Porcu Date: Mon, 6 Feb 2023 09:29:04 -0800 Subject: [PATCH 051/240] Empty payload for heartbeating in frequent polling activities (#412) * empty heartbeat message * Fixing formatting * Implementing fix from PR * Import cleanup --- .../samples/polling/frequent/FrequentPollingActivityImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java b/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java index 1e812473f..fe3c85e5b 100644 --- a/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java +++ b/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java @@ -48,7 +48,7 @@ public String doPoll() { // heart beat and sleep for the poll duration try { - context.heartbeat("no response"); + context.heartbeat(null); } catch (ActivityCompletionException e) { // activity was either cancelled or workflow was completed or worker shut down throw e; From b3a033885789df2b51c135233aeecfa66d6f7444 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Mon, 6 Feb 2023 13:30:11 -0500 Subject: [PATCH 052/240] Update activity options for PeriodicPollingChildWorkflow sample (#419) * Update activity options for PeriodicPollingChildWorkflow sample Signed-off-by: Tihomir Surdilovic * update comments Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- .../PeriodicPollingChildWorkflowImpl.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java b/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java index 0f4080212..a877946ee 100644 --- a/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java +++ b/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java @@ -20,6 +20,7 @@ package io.temporal.samples.polling.periodicsequence; import io.temporal.activity.ActivityOptions; +import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.samples.polling.PollingActivities; import io.temporal.workflow.Workflow; @@ -34,7 +35,12 @@ public String exec(int pollingIntervalInSeconds) { PollingActivities activities = Workflow.newActivityStub( PollingActivities.class, - ActivityOptions.newBuilder().setScheduleToCloseTimeout(Duration.ofSeconds(4)).build()); + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(4)) + // Explicitly disable default retries for activities + // as activity retries are handled with business logic in this case + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) + .build()); for (int i = 0; i < singleWorkflowPollAttempts; i++) { // Here we would invoke a sequence of activities From 4a29766827e28ee558511a48293e4591f7bbcd78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:57:52 -0500 Subject: [PATCH 053/240] Bump io.cloudevents:cloudevents-json-jackson from 2.4.0 to 2.4.1 (#420) Bumps io.cloudevents:cloudevents-json-jackson from 2.4.0 to 2.4.1. --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-json-jackson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b435118ea..fcf92da7e 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.0' - implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.0' + implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.1' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' From d991139c396f2f301a35ef585646c1c486b7be60 Mon Sep 17 00:00:00 2001 From: Dave Eason <125314961+DaveyBoy57@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:00:54 -0600 Subject: [PATCH 054/240] Updated README.md to correct default port for Temporal Server from 8088 (old) to 8080 (new) (#425) Co-authored-by: Dave Eason --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6393d2cf4..85d590327 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,10 @@ Note that in this case you should use the [Temporal CLI (tctl)](https://docs.tem ## Temporal Web UI -The Temporal Server running in a docker container includes a Web UI, exposed by default on port 8088 of the docker host. +The Temporal Server running in a docker container includes a Web UI, exposed by default on port 8080 of the docker host. If you are running Docker on your host, you can connect to the WebUI running using a browser and opening the following URI: -[http://localhost:8088](http://localhost:8088) +[http://localhost:8080](http://localhost:8080) If you are running Docker on a different host (e.g.: a virtual machine), then modify the URI accordingly by specifying the correct host and the correct port. From 4218850bf50b7e28b9568d2ece0de4f76ed3e7cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 18:05:49 -0500 Subject: [PATCH 055/240] Bump io.cloudevents:cloudevents-api from 2.4.0 to 2.4.1 (#423) Bumps [io.cloudevents:cloudevents-api](https://github.com/cloudevents/sdk-java) from 2.4.0 to 2.4.1. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.4.0...2.4.1) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fcf92da7e..9ff2447ca 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ dependencies { implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.0' - implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.0' + implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.1' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.1' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' From 27469ab52a4aa011a4927343aec4db34448c0008 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 18:12:09 -0500 Subject: [PATCH 056/240] Bump io.cloudevents:cloudevents-core from 2.4.0 to 2.4.1 (#424) Bumps [io.cloudevents:cloudevents-core](https://github.com/cloudevents/sdk-java) from 2.4.0 to 2.4.1. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.4.0...2.4.1) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9ff2447ca..73cc79f10 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,7 @@ dependencies { implementation "com.fasterxml.jackson.core:jackson-databind" implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' - implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.0' + implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.1' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.1' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.1' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' From 96174b823ff5d22153b9afe24a77fec45d4b07e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:44:25 -0500 Subject: [PATCH 057/240] Bump com.diffplug.spotless from 6.12.1 to 6.15.0 (#427) Bumps com.diffplug.spotless from 6.12.1 to 6.15.0. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 73cc79f10..3abf2fb87 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.0.1" - id 'com.diffplug.spotless' version '6.12.1' apply false + id 'com.diffplug.spotless' version '6.15.0' apply false } apply plugin: 'java' From c52ec144afbc184f6ddf37465238b39ac929d87e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:44:55 -0500 Subject: [PATCH 058/240] Bump org.junit:junit-bom from 5.9.1 to 5.9.2 (#428) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.9.1 to 5.9.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.1...r5.9.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3abf2fb87..4bc930b2b 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ ext { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.1")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.22.0")) - implementation(platform("org.junit:junit-bom:5.9.1")) + implementation(platform("org.junit:junit-bom:5.9.2")) implementation "io.temporal:temporal-sdk:$javaSDKVersion" implementation "io.temporal:temporal-opentracing:$javaSDKVersion" From 91272721e68ed462f46b662f65ff603d9ac5c746 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:45:17 -0500 Subject: [PATCH 059/240] Bump com.fasterxml.jackson:jackson-bom from 2.14.1 to 2.14.2 (#429) Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.14.1 to 2.14.2. - [Release notes](https://github.com/FasterXML/jackson-bom/releases) - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.14.1...jackson-bom-2.14.2) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4bc930b2b..44ae4f171 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ ext { } dependencies { - implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.1")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.2")) implementation(platform("io.opentelemetry:opentelemetry-bom:1.22.0")) implementation(platform("org.junit:junit-bom:5.9.2")) From d40e609a78ee2cfb360c0a1ff50c2abf30a62423 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:59:40 -0500 Subject: [PATCH 060/240] Bump io.opentelemetry:opentelemetry-bom from 1.22.0 to 1.23.1 (#430) Bumps [io.opentelemetry:opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.22.0 to 1.23.1. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.22.0...v1.23.1) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 44ae4f171..98480c8d0 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ ext { dependencies { implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.2")) - implementation(platform("io.opentelemetry:opentelemetry-bom:1.22.0")) + implementation(platform("io.opentelemetry:opentelemetry-bom:1.23.1")) implementation(platform("org.junit:junit-bom:5.9.2")) implementation "io.temporal:temporal-sdk:$javaSDKVersion" From 312b8ca7bf477b79b493ee206713d619da1ddd6f Mon Sep 17 00:00:00 2001 From: Dave Eason <125314961+DaveyBoy57@users.noreply.github.com> Date: Tue, 21 Feb 2023 11:26:58 -0600 Subject: [PATCH 061/240] Gradle 8 - use of 'main' in JavaExec deprecated, should be mainClass (#426) * Updated README.md to correct default port for Temporal Server from 8088 (old) to 8080 (new) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 98480c8d0..7c46bdce7 100644 --- a/build.gradle +++ b/build.gradle @@ -79,7 +79,7 @@ dependencies { } task execute(type: JavaExec) { - main = findProperty("mainClass") ?: "" + mainClass = findProperty("mainClass") ?: "" classpath = sourceSets.main.runtimeClasspath } From 3f1b7fd0bedd449fea9592d1a5bd532d8ab607e8 Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Tue, 21 Feb 2023 13:50:48 -0500 Subject: [PATCH 062/240] Gradle 8 upgrade (#431) --- build.gradle | 40 +-- gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 61608 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 269 +++++++++++------- gradlew.bat | 15 +- .../samples/hello/HelloExceptionTest.java | 4 +- 6 files changed, 199 insertions(+), 132 deletions(-) diff --git a/build.gradle b/build.gradle index 7c46bdce7..1ff63d625 100644 --- a/build.gradle +++ b/build.gradle @@ -21,19 +21,36 @@ repositories { } ext { + otelVersion = '1.23.1' + otelVersionAlpha = "${otelVersion}-alpha" javaSDKVersion = '1.18.1' } dependencies { - implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.2")) - implementation(platform("io.opentelemetry:opentelemetry-bom:1.23.1")) - implementation(platform("org.junit:junit-bom:5.9.2")) - + // Temporal SDK implementation "io.temporal:temporal-sdk:$javaSDKVersion" implementation "io.temporal:temporal-opentracing:$javaSDKVersion" + testImplementation("io.temporal:temporal-testing:$javaSDKVersion") + // Needed for SDK related functionality + implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.2")) implementation "com.fasterxml.jackson.core:jackson-databind" + implementation "com.fasterxml.jackson.core:jackson-core" + + implementation "io.micrometer:micrometer-registry-prometheus" + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' + implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.7.0' + + implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) + implementation "io.opentelemetry:opentelemetry-sdk" + implementation "io.opentelemetry:opentelemetry-exporter-jaeger" + implementation "io.opentelemetry:opentelemetry-extension-trace-propagators" + implementation "io.opentelemetry:opentelemetry-opentracing-shim:$otelVersionAlpha" + implementation "io.opentelemetry:opentelemetry-semconv:$otelVersionAlpha" + implementation 'io.jaegertracing:jaeger-client:1.8.1' + + // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.1' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.1' @@ -42,28 +59,15 @@ dependencies { implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.3.Final' - implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.7.0' - implementation "io.micrometer:micrometer-registry-prometheus" implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20220705' - implementation "com.fasterxml.jackson.core:jackson-core" - implementation 'io.jaegertracing:jaeger-client:1.8.1' - - - implementation "io.opentelemetry:opentelemetry-sdk" - implementation "io.opentelemetry:opentelemetry-exporter-jaeger" - implementation "io.opentelemetry:opentelemetry-extension-trace-propagators" - implementation 'io.opentelemetry:opentelemetry-opentracing-shim:1.14.0-alpha' - implementation 'io.opentelemetry:opentelemetry-semconv:1.14.0-alpha' // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' - testImplementation("io.temporal:temporal-testing:$javaSDKVersion") - testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:5.1.1" - testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' + testImplementation(platform("org.junit:junit-bom:5.9.2")) testImplementation "org.junit.jupiter:junit-jupiter-api" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" testRuntimeOnly "org.junit.vintage:junit-vintage-engine" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..ccebba7710deaf9f98673a68957ea02138b60d0a 100644 GIT binary patch delta 39624 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 delta 37640 zcmY(pV{oQl@UEMQIdLYoZQHhO+nPMFZN0H=PmGB*$wZUnjWaPO#`&H7-?h&^-+I;R zs`a5)RbSorT?K|pUW9^CRe*v?z)jk`3-v@h+Kh<+Z{*45LEsZ32p!?75|!v%;9<=FBo{3 zRXe7ZM! z98qkC_kq3Jr|u(PUJ~iwCsJ*p-a(%Pqgj9Xc7Lc+p}K;6c)u(#FRF9=)wo4iY?p4? z60^8uurIVZQIm2}Ce`pi{UcuL|JWR#Q8Q{kW;nuMAGNtQh~oc6&3J6c<$o3S|5VZL z3u7$_36WS~;2Z71buHB@aK)V3L^u?)d zgL#sy&e{9ax^%(*s{V)IV@T%*!UNSBd;4;hcLk8Pe=pE0CuiO_IJ4fm^Y77!=TrFo zoh`WZNlqF9lihd(2H~4Tb~-DS1^(64wO9r#g_*WAa+amxcmVrRGJrkN7mtQxX*i_i z)<+_)tlALaYBUUoq0Ua;MP@iVh_L|~D(37j(?wz? zH)m`19Dj#1&V*2`b2-ZiEQ!yJt#^vxxg*64X#g`#J%-t-v$plgb=PvP(#c)s>9y7b zia~oDB#rs6W!COA<7^EAUGZ+oDkF@MMA#i>xh|YHyh}y{7$8zNEO<5xxxiDLg$P4b-Y1$G*5>uV zUS3pq1J;l+0lZpsti6iEQIx5uk^MRLBoj{ttVWACl|oS5nKj68VY0Gc7aeC$BJ8jj zOJY7VO(CumzCL^t5jhn@iNu|q84KnD=<_A zdu!zT6mz@J)LDflk;4=e9Y)D6N1$>&y?&_rrn(jkV6v+KV*+;gTjsyS5vg@l(vR3b zWJ+XMkIxyWiTvfj0A>dq5_)wLTyc&a<+vLiN^(sxvcN#kdN14v*xh#Mq8y&vfu!{* z6*7&MY+F>Q3qUL5H~;=>yDT2XY_CY`)P)3FFwH2X>`1n_*;bC{o$+g>X%?nvM%-jh z{Su%6)DM)s>(8&%@BC#c4QMzLh#-smk-I+w3c6 zvKP8e?Wjtrs`6uFL54F}HGH*3xYgPqw0cYfyc3EwSa=vazJ~dV>jie^&gSULF$&&* z9()2Rpu znE8a?Ed8MOFZsAmq#w2ju_f(GE2H2u@zv>w{bMm?o9u@pbMk$DrRtOAzCj}K1&~M= z3x4P=(l{yeU=jNh_4U5EFo-vvA`w}tQT>g_4UH=Hhxpp zUz@=oXPTamj%0)trn)RGmcHmFJ|vYE1EQUS0VzJdJQbE??HpA%$|iGf*ShFur0~

hZ6yjbL-Opwj#IyQ(UF?vIf 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 H_^bZ|3zHqB diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa991fcea..fc10b601f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882ed..79a61d421 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright Β© 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions Β«$varΒ», Β«${var}Β», Β«${var:-default}Β», Β«${var+SET}Β», +# Β«${var#prefix}Β», Β«${var%suffix}Β», and Β«$( cmd )Β»; +# * compound commands having a testable exit status, especially Β«caseΒ»; +# * various built-in commands including Β«commandΒ», Β«setΒ», and Β«ulimitΒ». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index ac1b06f93..6689b85be 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java b/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java index ea98dc0e6..84f95fa6d 100644 --- a/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java +++ b/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java @@ -22,8 +22,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyString; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.when; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import io.temporal.api.enums.v1.TimeoutType; import io.temporal.client.WorkflowException; From 9acdf65c087b7ab8fddbf25cb05728ec8235b37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Tue, 28 Feb 2023 09:52:44 +0100 Subject: [PATCH 063/240] fix class name --- src/main/java/io/temporal/samples/batch/slidingwindow/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/README.md b/src/main/java/io/temporal/samples/batch/slidingwindow/README.md index 89ab80ced..ef85b7555 100644 --- a/src/main/java/io/temporal/samples/batch/slidingwindow/README.md +++ b/src/main/java/io/temporal/samples/batch/slidingwindow/README.md @@ -15,7 +15,7 @@ The sample has two executables. Execute each command in a separate terminal wind The first command runs the Worker that hosts the Workflow and Activity Executions. ```bash -./gradlew -q execute -PmainClass=io.temporal.samples.batch.hslidingwindow.SlidingWindowBatchWorkflowWorker +./gradlew -q execute -PmainClass=io.temporal.samples.batch.slidingwindow.SlidingWindowBatchWorker ``` Note that `Caused by: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: UnhandledCommand` info messages in the output From cb78ebce84f7f3346bc0584282a34d06b21181f2 Mon Sep 17 00:00:00 2001 From: Dmitry Spikhalskiy Date: Fri, 17 Mar 2023 14:39:45 -0400 Subject: [PATCH 064/240] Update to Java SDK v1.19.0 (#438) --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 1ff63d625..cbae3b6c3 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.0.1" - id 'com.diffplug.spotless' version '6.15.0' apply false + id 'com.diffplug.spotless' version '6.17.0' apply false } apply plugin: 'java' @@ -21,9 +21,9 @@ repositories { } ext { - otelVersion = '1.23.1' + otelVersion = '1.24.0' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.18.1' + javaSDKVersion = '1.19.0' } dependencies { @@ -105,7 +105,7 @@ if (JavaVersion.current().isJava11Compatible()) { java { target 'src/*/java/**/*.java' targetExclude '**/.idea/**' - googleJavaFormat('1.15.0') + googleJavaFormat('1.16.0') } } From 93555299b8392892cd8319b492d7a8ed1e5d2f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Mon, 15 May 2023 15:43:06 +0200 Subject: [PATCH 065/240] add test HelloSearchAttributes (#443) --- .../samples/hello/HelloSearchAttributes.java | 6 +- .../hello/HelloSearchAttributesTest.java | 93 +++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java diff --git a/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java b/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java index bd54549b6..9dfabdd07 100644 --- a/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java +++ b/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java @@ -207,7 +207,7 @@ public static void main(String[] args) { // Get the specific value of a keyword from the payload. // In this case it is the "CustomKeywordField" with the value of "keys" // You can update the code to extract other defined search attribute as well - String keyword = getKeywordFromSearchAttribute(searchAttributes); + String keyword = getKeywordFromSearchAttribute(searchAttributes, "CustomKeywordField"); // Print the value of the "CustomKeywordField" field System.out.printf("In workflow we get CustomKeywordField is: %s\n", keyword); } catch (Exception e) { @@ -242,8 +242,8 @@ private static String generateDateTimeFieldValue() { } // example for extracting a value from search attributes - private static String getKeywordFromSearchAttribute(SearchAttributes searchAttributes) { - Payload field = searchAttributes.getIndexedFieldsOrThrow("CustomKeywordField"); + static String getKeywordFromSearchAttribute(SearchAttributes searchAttributes, String key) { + Payload field = searchAttributes.getIndexedFieldsOrThrow(key); DataConverter dataConverter = GlobalDataConverter.get(); return dataConverter.fromPayload(field, String.class, String.class); } diff --git a/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java b/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java new file mode 100644 index 000000000..40fd62264 --- /dev/null +++ b/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static io.temporal.samples.hello.HelloSearchAttributes.getKeywordFromSearchAttribute; + +import io.temporal.api.common.v1.SearchAttributes; +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionRequest; +import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionResponse; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.testing.TestWorkflowRule; +import java.util.Map; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +/** Unit test for {@link HelloSearchAttributes}. Doesn't use an external Temporal service. */ +public class HelloSearchAttributesTest { + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(HelloSearchAttributes.GreetingWorkflowImpl.class) + .setDoNotStart(true) + .build(); + + @Test + public void testStartWorkflowWithSearchAttribute() { + + final String taskQueue = testWorkflowRule.getTaskQueue(); + final String workflowId = "workflowId"; + final String customKeywordField = "CustomKeywordField"; + final String customKeywordValue = "CustomKeywordValue"; + + testWorkflowRule + .getWorker() + .registerActivitiesImplementations(new HelloSearchAttributes.GreetingActivitiesImpl()); + testWorkflowRule.getTestEnvironment().start(); + + // Get a workflow stub using the same task queue the worker uses. + final HelloSearchAttributes.GreetingWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloSearchAttributes.GreetingWorkflow.class, + WorkflowOptions.newBuilder() + .setSearchAttributes(Map.of(customKeywordField, customKeywordValue)) + .setWorkflowId(workflowId) + .setTaskQueue(taskQueue) + .build()); + + final WorkflowStub untyped = WorkflowStub.fromTyped(workflow); + final WorkflowExecution execution = untyped.start("Hello"); + + // wait until workflow completes + untyped.getResult(String.class); + + final DescribeWorkflowExecutionResponse resp = + testWorkflowRule + .getWorkflowClient() + .getWorkflowServiceStubs() + .blockingStub() + .describeWorkflowExecution( + DescribeWorkflowExecutionRequest.newBuilder() + .setNamespace(testWorkflowRule.getTestEnvironment().getNamespace()) + .setExecution(execution) + .build()); + // get all search attributes + final SearchAttributes searchAttributes = resp.getWorkflowExecutionInfo().getSearchAttributes(); + + Assert.assertEquals( + customKeywordValue, getKeywordFromSearchAttribute(searchAttributes, customKeywordField)); + } +} From 82a26a84957ba7494f8a9b9e7480df9b3a564bed Mon Sep 17 00:00:00 2001 From: "mend-for-github-com[bot]" <50673670+mend-for-github-com[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 09:53:40 -0400 Subject: [PATCH 066/240] Update dependency com.jayway.jsonpath:json-path to v2.8.0 (#442) Co-authored-by: mend-for-github-com[bot] <50673670+mend-for-github-com[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cbae3b6c3..37816df7e 100644 --- a/build.gradle +++ b/build.gradle @@ -40,7 +40,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' - implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.7.0' + implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) implementation "io.opentelemetry:opentelemetry-sdk" From 1b2adeb0999ef808e84f0cfb7d21f7efe5a81f06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 09:54:15 -0400 Subject: [PATCH 067/240] Bump io.cloudevents:cloudevents-core from 2.4.1 to 2.4.2 (#434) Bumps [io.cloudevents:cloudevents-core](https://github.com/cloudevents/sdk-java) from 2.4.1 to 2.4.2. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.4.1...2.4.2) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 37816df7e..63021aa81 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' - implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.1' + implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.2' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.1' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.1' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' From eb2b12026a4000085c1a6a2a2848126523f422d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 10:04:32 -0400 Subject: [PATCH 068/240] Bump io.cloudevents:cloudevents-api from 2.4.1 to 2.4.2 (#435) Bumps [io.cloudevents:cloudevents-api](https://github.com/cloudevents/sdk-java) from 2.4.1 to 2.4.2. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.4.1...2.4.2) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 63021aa81..68ccc165a 100644 --- a/build.gradle +++ b/build.gradle @@ -52,8 +52,9 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' + implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.2' - implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.1' + implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.2' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.1' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' From 99a6c82c5d3293074753ae83a1392f88f4e103c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 10:08:31 -0400 Subject: [PATCH 069/240] Bump io.cloudevents:cloudevents-json-jackson from 2.4.1 to 2.4.2 (#437) Bumps io.cloudevents:cloudevents-json-jackson from 2.4.1 to 2.4.2. --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-json-jackson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 68ccc165a..6aad72479 100644 --- a/build.gradle +++ b/build.gradle @@ -52,10 +52,9 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' - implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.2' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.2' - implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.1' + implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.2' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' From 28bbdb22712d001a66cd5e4c303fe6b00288f874 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 10:09:16 -0400 Subject: [PATCH 070/240] Bump org.mockito:mockito-core from 5.1.1 to 5.3.1 (#446) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.1.1 to 5.3.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.1.1...v5.3.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6aad72479..f4d812f9e 100644 --- a/build.gradle +++ b/build.gradle @@ -65,7 +65,7 @@ dependencies { implementation 'com.codingrodent:jackson-json-crypto:1.1.0' testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.1.1" + testImplementation "org.mockito:mockito-core:5.3.1" testImplementation(platform("org.junit:junit-bom:5.9.2")) testImplementation "org.junit.jupiter:junit-jupiter-api" From df3113fd33cc8d62a76af4ba56e5c2125c7308c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 10:09:45 -0400 Subject: [PATCH 071/240] Bump ch.qos.logback:logback-classic from 1.2.11 to 1.4.7 (#447) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.2.11 to 1.4.7. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.2.11...v_1.4.7) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f4d812f9e..4570f3dea 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.7' implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) From 1a751ed70aa7fa742d500b57f7d24b1113a5315c Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Wed, 24 May 2023 14:10:56 -0400 Subject: [PATCH 072/240] Update to Java SDK v1.19.1 (#449) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4570f3dea..cfd3a8c6e 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ repositories { ext { otelVersion = '1.24.0' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.19.0' + javaSDKVersion = '1.19.1' } dependencies { From 345bd6e0ee39bba52dd6de7a9c3f59cac050a9a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 18:36:31 -0400 Subject: [PATCH 073/240] Bump org.junit:junit-bom from 5.9.2 to 5.9.3 (#451) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.9.2 to 5.9.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.2...r5.9.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cfd3a8c6e..6571042e7 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ dependencies { testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:5.3.1" - testImplementation(platform("org.junit:junit-bom:5.9.2")) + testImplementation(platform("org.junit:junit-bom:5.9.3")) testImplementation "org.junit.jupiter:junit-jupiter-api" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" testRuntimeOnly "org.junit.vintage:junit-vintage-engine" From ce356ffb611eed3b44d7ba8e3da0b9579a623221 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 18:36:54 -0400 Subject: [PATCH 074/240] Bump io.cloudevents:cloudevents-core from 2.4.2 to 2.5.0 (#452) Bumps [io.cloudevents:cloudevents-core](https://github.com/cloudevents/sdk-java) from 2.4.2 to 2.5.0. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.4.2...2.5.0) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6571042e7..e3aa4aaab 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' - implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.4.2' + implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.2' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.2' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' From 2e76bb0b667dd0a060d92fb691a2dae565725947 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 18:37:18 -0400 Subject: [PATCH 075/240] Bump net.ltgt.errorprone from 3.0.1 to 3.1.0 (#453) Bumps net.ltgt.errorprone from 3.0.1 to 3.1.0. --- updated-dependencies: - dependency-name: net.ltgt.errorprone dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e3aa4aaab..0ff07b6f2 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' - id "net.ltgt.errorprone" version "3.0.1" + id "net.ltgt.errorprone" version "3.1.0" id 'com.diffplug.spotless' version '6.17.0' apply false } From aef30c513ae6a055e0d041a3a5ca56616a41ed02 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 18:37:44 -0400 Subject: [PATCH 076/240] Bump io.opentelemetry:opentelemetry-bom from 1.24.0 to 1.26.0 (#454) Bumps [io.opentelemetry:opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.24.0 to 1.26.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.24.0...v1.26.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0ff07b6f2..64d7dae4c 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ repositories { } ext { - otelVersion = '1.24.0' + otelVersion = '1.26.0' otelVersionAlpha = "${otelVersion}-alpha" javaSDKVersion = '1.19.1' } From 4db79e0f91e2b4b58528bd26bda6b0dc6f5fc2dc Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Sat, 27 May 2023 12:33:32 -0400 Subject: [PATCH 077/240] Sample - simple payload coded use to encode/decode failure messages (#455) * Sample - simple payload coded use to encode/decide failure messages Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * update to Starter Signed-off-by: Tihomir Surdilovic * remove unused annotations on model Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 2 + .../encodefailures/CustomerAgeCheck.java | 29 +++++ .../encodefailures/CustomerAgeCheckImpl.java | 36 ++++++ .../InvalidCustomerException.java | 26 ++++ .../samples/encodefailures/MyCustomer.java | 57 +++++++++ .../temporal/samples/encodefailures/README.md | 28 +++++ .../SimplePrefixPayloadCodec.java | 62 ++++++++++ .../samples/encodefailures/Starter.java | 111 ++++++++++++++++++ .../encodefailures/EncodeFailuresTest.java | 91 ++++++++++++++ 9 files changed, 442 insertions(+) create mode 100644 src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java create mode 100644 src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java create mode 100644 src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java create mode 100644 src/main/java/io/temporal/samples/encodefailures/MyCustomer.java create mode 100644 src/main/java/io/temporal/samples/encodefailures/README.md create mode 100644 src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java create mode 100644 src/main/java/io/temporal/samples/encodefailures/Starter.java create mode 100644 src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java diff --git a/README.md b/README.md index 85d590327..4d94e6942 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,8 @@ All tests are available under [src/test/java](./src/test/java/io/temporal/sample - [**Configure WorkflowClient to use mTLS**](./src/main/java/io/temporal/samples/ssl): Demonstrates how to configure WorkflowClient when using mTLS. +- [**Payload Codec**](./src/main/java/io/temporal/samples/encodefailures): Demonstrates how to use simple codec to encode/decode failure messages. + ### SDK Metrics - [**Set up SDK metrics**](./src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics. diff --git a/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java b/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java new file mode 100644 index 000000000..d302fc8fe --- /dev/null +++ b/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.encodefailures; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface CustomerAgeCheck { + @WorkflowMethod + public String validateCustomer(MyCustomer customer); +} diff --git a/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java b/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java new file mode 100644 index 000000000..ab3571c5d --- /dev/null +++ b/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.encodefailures; + +import io.temporal.workflow.Workflow; + +public class CustomerAgeCheckImpl implements CustomerAgeCheck { + @Override + public String validateCustomer(MyCustomer customer) { + // Note we have explicitly set InvalidCustomerException type to fail workflow execution + // We wrap it using Workflow.wrap so can throw as unchecked + if (customer.getAge() < 21) { + throw Workflow.wrap( + new InvalidCustomerException("customer " + customer.getName() + " is under age.")); + } else { + return "done..."; + } + } +} diff --git a/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java b/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java new file mode 100644 index 000000000..d8eefbdd5 --- /dev/null +++ b/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.encodefailures; + +public class InvalidCustomerException extends Exception { + public InvalidCustomerException(String errorMessage) { + super(errorMessage); + } +} diff --git a/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java b/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java new file mode 100644 index 000000000..30a6def44 --- /dev/null +++ b/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.encodefailures; + +public class MyCustomer { + private String name; + private int age; + private boolean approved; + + public MyCustomer() {} + + public MyCustomer(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public boolean isApproved() { + return approved; + } + + public void setApproved(boolean approved) { + this.approved = approved; + } +} diff --git a/src/main/java/io/temporal/samples/encodefailures/README.md b/src/main/java/io/temporal/samples/encodefailures/README.md new file mode 100644 index 000000000..9fc373a2b --- /dev/null +++ b/src/main/java/io/temporal/samples/encodefailures/README.md @@ -0,0 +1,28 @@ +# Using Codec to encode / decode failure messages + +The sample demonstrates how to set up a simple codec for encoding/decoding failure messages +In this sample we set encodeFailureAttributes = true to our CodecDataConverter meaning we want to +encode / decode failure messages as well. +All it does is add a "Customer: " prefix to the message. You can expand on this to add any type of +encoding that you might want to use. + +Our workflow does simple customer age check validation and fails if their age is < 21. +In the Starter then we print out that the failure message client received on execution failure +was indeed encoded using our codec. + +## Running + +1. Start Temporal Server with "default" namespace enabled. + For example using local Docker: + +```bash +git clone https://github.com/temporalio/docker-compose.git +cd docker-compose +docker-compose up +``` + +2. Run the following command to start the sample: + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.encodefailures.Starter +``` diff --git a/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java b/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java new file mode 100644 index 000000000..a25bccef4 --- /dev/null +++ b/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.encodefailures; + +import com.google.protobuf.ByteString; +import io.temporal.api.common.v1.Payload; +import io.temporal.payload.codec.PayloadCodec; +import io.temporal.payload.codec.PayloadCodecException; +import java.util.List; +import java.util.stream.Collectors; +import org.jetbrains.annotations.NotNull; + +/** + * Simple codec that adds dummy prefix to payload. For this sample it's also applied for failure + * messages. + */ +public class SimplePrefixPayloadCodec implements PayloadCodec { + + public static final ByteString PREFIX = ByteString.copyFromUtf8("Customer: "); + + @NotNull + @Override + public List encode(@NotNull List payloads) { + return payloads.stream().map(this::encode).collect(Collectors.toList()); + } + + private Payload encode(Payload decodedPayload) { + ByteString encodedData = PREFIX.concat(decodedPayload.getData()); + return decodedPayload.toBuilder().setData(encodedData).build(); + } + + @NotNull + @Override + public List decode(@NotNull List payloads) { + return payloads.stream().map(this::decode).collect(Collectors.toList()); + } + + private Payload decode(Payload encodedPayload) { + ByteString encodedData = encodedPayload.getData(); + if (!encodedData.startsWith(PREFIX)) + throw new PayloadCodecException("Payload is not correctly encoded"); + ByteString decodedData = encodedData.substring(PREFIX.size()); + return encodedPayload.toBuilder().setData(decodedData).build(); + } +} diff --git a/src/main/java/io/temporal/samples/encodefailures/Starter.java b/src/main/java/io/temporal/samples/encodefailures/Starter.java new file mode 100644 index 000000000..5bdd35888 --- /dev/null +++ b/src/main/java/io/temporal/samples/encodefailures/Starter.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.encodefailures; + +import io.temporal.api.common.v1.Payload; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.converter.CodecDataConverter; +import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkflowImplementationOptions; +import java.util.Collections; + +public class Starter { + private static final String TASK_QUEUE = "EncodeDecodeFailuresTaskQueue"; + private static final String WORKFLOW_ID = "CustomerValidationWorkflow"; + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + // CodecDataConverter defines our data converter and codec + // sets encodeFailureAttributes to true + CodecDataConverter codecDataConverter = + new CodecDataConverter( + // For sample we just use default data converter + DefaultDataConverter.newDefaultInstance(), + // Simple prefix codec to encode/decode + Collections.singletonList(new SimplePrefixPayloadCodec()), + true); // Setting encodeFailureAttributes to true + + // WorkflowClient uses our CodecDataConverter + WorkflowClient client = + WorkflowClient.newInstance( + service, + WorkflowClientOptions.newBuilder().setDataConverter(codecDataConverter).build()); + + // Create worker and start Worker factory + createWorker(client); + + // Start workflow execution and catch client error (workflow execution fails) + CustomerAgeCheck workflow = + client.newWorkflowStub( + CustomerAgeCheck.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + try { + // Start workflow execution to validate under-age customer + workflow.validateCustomer(new MyCustomer("John", 17)); + System.out.println("Workflow should have failed on customer validation"); + } catch (WorkflowFailedException e) { + // Get failure message from last event in history (WorkflowExecutionFailed event) and check + // that + // its encoded + HistoryEvent wfExecFailedEvent = client.fetchHistory(WORKFLOW_ID).getLastEvent(); + Payload payload = + wfExecFailedEvent + .getWorkflowExecutionFailedEventAttributes() + .getFailure() + .getEncodedAttributes(); + if (isEncoded(payload)) { + System.out.println("Workflow failure was encoded"); + } else { + System.out.println("Workflow failure was not encoded"); + } + } + + // Stop sample + System.exit(0); + } + + private static boolean isEncoded(Payload payload) { + return payload.getData().startsWith(SimplePrefixPayloadCodec.PREFIX); + } + + private static void createWorker(WorkflowClient client) { + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(TASK_QUEUE); + worker.registerWorkflowImplementationTypes( + WorkflowImplementationOptions.newBuilder() + // note we set InvalidCustomerException to fail execution + .setFailWorkflowExceptionTypes(InvalidCustomerException.class) + .build(), + CustomerAgeCheckImpl.class); + factory.start(); + } +} diff --git a/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java b/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java new file mode 100644 index 000000000..24985a7bf --- /dev/null +++ b/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.encodefailures; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import io.temporal.api.common.v1.Payload; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.converter.CodecDataConverter; +import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.testing.TestWorkflowRule; +import io.temporal.worker.WorkflowImplementationOptions; +import java.util.Collections; +import org.junit.Rule; +import org.junit.Test; + +public class EncodeFailuresTest { + + CodecDataConverter codecDataConverter = + new CodecDataConverter( + DefaultDataConverter.newDefaultInstance(), + Collections.singletonList(new SimplePrefixPayloadCodec()), + true); + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes( + WorkflowImplementationOptions.newBuilder() + .setFailWorkflowExceptionTypes(InvalidCustomerException.class) + .build(), + CustomerAgeCheckImpl.class) + .setWorkflowClientOptions( + WorkflowClientOptions.newBuilder().setDataConverter(codecDataConverter).build()) + .build(); + + @Test + public void testFailureMessageIsEncoded() { + + CustomerAgeCheck workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + CustomerAgeCheck.class, + WorkflowOptions.newBuilder() + .setWorkflowId("CustomerAgeCheck") + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build()); + + WorkflowFailedException exception = + assertThrows( + WorkflowFailedException.class, + () -> { + workflow.validateCustomer(new MyCustomer("John", 20)); + }); + + HistoryEvent wfExecFailedEvent = + testWorkflowRule.getWorkflowClient().fetchHistory("CustomerAgeCheck").getLastEvent(); + Payload payload = + wfExecFailedEvent + .getWorkflowExecutionFailedEventAttributes() + .getFailure() + .getEncodedAttributes(); + assertTrue(isEncoded(payload)); + } + + private boolean isEncoded(Payload payload) { + return payload.getData().startsWith(SimplePrefixPayloadCodec.PREFIX); + } +} From 3e55d09936969674bc89e3b3b454caa4dd6fbd59 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Wed, 7 Jun 2023 11:28:09 -0400 Subject: [PATCH 078/240] SpringBoot sample (and project refactor) (#464) * SpringBoot sample (and project refactor) Signed-off-by: Tihomir Surdilovic * added comment in application.yaml Signed-off-by: Tihomir Surdilovic * updates to readme and gitignore Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- .gitignore | 4 + README.md | 216 +++++++----------- build.gradle | 136 ++++------- core/build.gradle | 60 +++++ .../samples/asyncchild/ChildWorkflow.java | 0 .../samples/asyncchild/ChildWorkflowImpl.java | 0 .../samples/asyncchild/ParentWorkflow.java | 0 .../asyncchild/ParentWorkflowImpl.java | 0 .../io/temporal/samples/asyncchild/README.md | 0 .../temporal/samples/asyncchild/Starter.java | 0 .../HeartbeatingActivityBatchStarter.java | 0 .../HeartbeatingActivityBatchWorker.java | 0 .../HeartbeatingActivityBatchWorkflow.java | 0 ...HeartbeatingActivityBatchWorkflowImpl.java | 0 .../batch/heartbeatingactivity/README.md | 0 .../heartbeatingactivity/RecordLoader.java | 0 .../RecordLoaderImpl.java | 0 .../heartbeatingactivity/RecordProcessor.java | 0 .../RecordProcessorActivity.java | 0 .../RecordProcessorActivityImpl.java | 0 .../RecordProcessorImpl.java | 0 .../heartbeatingactivity/SingleRecord.java | 0 .../batch/iterator/IteratorBatchStarter.java | 0 .../batch/iterator/IteratorBatchWorker.java | 0 .../batch/iterator/IteratorBatchWorkflow.java | 0 .../iterator/IteratorBatchWorkflowImpl.java | 0 .../temporal/samples/batch/iterator/README.md | 0 .../samples/batch/iterator/RecordLoader.java | 0 .../batch/iterator/RecordLoaderImpl.java | 0 .../iterator/RecordProcessorWorkflow.java | 0 .../iterator/RecordProcessorWorkflowImpl.java | 0 .../samples/batch/iterator/SingleRecord.java | 0 .../batch/slidingwindow/BatchProgress.java | 0 .../batch/slidingwindow/BatchWorkflow.java | 0 .../slidingwindow/BatchWorkflowImpl.java | 0 .../slidingwindow/ProcessBatchInput.java | 0 .../samples/batch/slidingwindow/README.md | 0 .../batch/slidingwindow/RecordIterable.java | 0 .../batch/slidingwindow/RecordLoader.java | 0 .../batch/slidingwindow/RecordLoaderImpl.java | 0 .../RecordProcessorWorkflow.java | 0 .../RecordProcessorWorkflowImpl.java | 0 .../batch/slidingwindow/SingleRecord.java | 0 .../SlidingWindowBatchStarter.java | 0 .../SlidingWindowBatchWorker.java | 0 .../SlidingWindowBatchWorkflow.java | 0 .../SlidingWindowBatchWorkflowImpl.java | 0 .../io/temporal/samples/bookingsaga/README.md | 0 .../bookingsaga/TripBookingActivities.java | 0 .../TripBookingActivitiesImpl.java | 0 .../samples/bookingsaga/TripBookingSaga.java | 0 .../bookingsaga/TripBookingWorkflow.java | 0 .../bookingsaga/TripBookingWorkflowImpl.java | 0 .../common/QueryWorkflowExecution.java | 0 .../countinterceptor/ClientCounter.java | 0 .../countinterceptor/InterceptorStarter.java | 0 .../samples/countinterceptor/README.md | 0 .../SimpleClientCallsInterceptor.java | 0 .../SimpleClientInterceptor.java | 0 ...eCountActivityInboundCallsInterceptor.java | 0 .../SimpleCountWorkerInterceptor.java | 0 ...eCountWorkflowInboundCallsInterceptor.java | 0 ...CountWorkflowOutboundCallsInterceptor.java | 0 .../countinterceptor/WorkerCounter.java | 0 .../activities/MyActivities.java | 0 .../activities/MyActivitiesImpl.java | 0 .../workflow/MyChildWorkflow.java | 0 .../workflow/MyChildWorkflowImpl.java | 0 .../countinterceptor/workflow/MyWorkflow.java | 0 .../workflow/MyWorkflowImpl.java | 0 .../temporal/samples/dsl/DslActivities.java | 0 .../samples/dsl/DslActivitiesImpl.java | 0 .../samples/dsl/DslWorkflowCache.java | 0 .../samples/dsl/DynamicDslWorkflow.java | 0 .../java/io/temporal/samples/dsl/README.md | 0 .../java/io/temporal/samples/dsl/Starter.java | 0 .../java/io/temporal/samples/dsl/Worker.java | 0 .../temporal/samples/dsl/model/ActResult.java | 0 .../temporal/samples/dsl/model/Customer.java | 0 .../samples/dsl/model/WorkflowData.java | 0 .../samples/dsl/utils/DslWorkflowUtils.java | 0 .../temporal/samples/dsl/utils/JQFilter.java | 0 .../encodefailures/CustomerAgeCheck.java | 0 .../encodefailures/CustomerAgeCheckImpl.java | 0 .../InvalidCustomerException.java | 0 .../samples/encodefailures/MyCustomer.java | 0 .../temporal/samples/encodefailures/README.md | 0 .../SimplePrefixPayloadCodec.java | 0 .../samples/encodefailures/Starter.java | 0 .../samples/encryptedpayloads/CryptCodec.java | 0 .../EncryptedPayloadsActivity.java | 0 .../fileprocessing/FileProcessingStarter.java | 0 .../fileprocessing/FileProcessingWorker.java | 0 .../FileProcessingWorkflow.java | 0 .../FileProcessingWorkflowImpl.java | 0 .../temporal/samples/fileprocessing/README.md | 0 .../fileprocessing/StoreActivities.java | 0 .../fileprocessing/StoreActivitiesImpl.java | 0 .../samples/getresultsasync/MyWorkflow.java | 0 .../getresultsasync/MyWorkflowImpl.java | 0 .../samples/getresultsasync/README.md | 0 .../samples/getresultsasync/Starter.java | 0 .../samples/getresultsasync/Worker.java | 0 .../temporal/samples/hello/HelloActivity.java | 0 .../hello/HelloActivityExclusiveChoice.java | 0 .../samples/hello/HelloActivityRetry.java | 0 .../io/temporal/samples/hello/HelloAsync.java | 0 .../hello/HelloAsyncActivityCompletion.java | 0 .../samples/hello/HelloAsyncLambda.java | 0 .../samples/hello/HelloCancellationScope.java | 0 .../io/temporal/samples/hello/HelloChild.java | 0 .../io/temporal/samples/hello/HelloCron.java | 0 .../hello/HelloDetachedCancellationScope.java | 0 .../temporal/samples/hello/HelloDynamic.java | 0 .../samples/hello/HelloException.java | 0 .../samples/hello/HelloLocalActivity.java | 0 .../samples/hello/HelloParallelActivity.java | 0 .../temporal/samples/hello/HelloPeriodic.java | 0 .../hello/HelloPolymorphicActivity.java | 0 .../io/temporal/samples/hello/HelloQuery.java | 0 .../io/temporal/samples/hello/HelloSaga.java | 0 .../samples/hello/HelloSearchAttributes.java | 0 .../samples/hello/HelloSideEffect.java | 0 .../temporal/samples/hello/HelloSignal.java | 0 .../java/io/temporal/samples/hello/README.md | 0 .../samples/listworkflows/Customer.java | 0 .../listworkflows/CustomerActivities.java | 0 .../listworkflows/CustomerActivitiesImpl.java | 0 .../listworkflows/CustomerWorkflow.java | 0 .../listworkflows/CustomerWorkflowImpl.java | 0 .../temporal/samples/listworkflows/README.md | 0 .../samples/listworkflows/Starter.java | 0 .../samples/metrics/MetricsStarter.java | 0 .../samples/metrics/MetricsUtils.java | 0 .../samples/metrics/MetricsWorker.java | 0 .../io/temporal/samples/metrics/README.md | 0 .../metrics/activities/MetricsActivities.java | 0 .../activities/MetricsActivitiesImpl.java | 0 .../metrics/workflow/MetricsWorkflow.java | 0 .../metrics/workflow/MetricsWorkflowImpl.java | 0 .../temporal/samples/moneybatch/Account.java | 0 .../moneybatch/AccountActivityWorker.java | 0 .../samples/moneybatch/AccountImpl.java | 0 .../moneybatch/AccountTransferWorker.java | 0 .../moneybatch/AccountTransferWorkflow.java | 0 .../AccountTransferWorkflowImpl.java | 0 .../io/temporal/samples/moneybatch/README.md | 0 .../samples/moneybatch/TransferRequester.java | 0 .../samples/moneytransfer/Account.java | 0 .../moneytransfer/AccountActivityWorker.java | 0 .../samples/moneytransfer/AccountImpl.java | 0 .../moneytransfer/AccountTransferWorker.java | 0 .../AccountTransferWorkflow.java | 0 .../AccountTransferWorkflowImpl.java | 0 .../temporal/samples/moneytransfer/README.MD | 0 .../moneytransfer/TransferRequester.java | 0 .../cloudevents/CEWorkflow.java | 0 .../cloudevents/CEWorkflowImpl.java | 0 .../CloudEventsPayloadConverter.java | 0 .../payloadconverter/cloudevents/README.md | 0 .../payloadconverter/cloudevents/Starter.java | 0 .../crypto/CryptoWorkflow.java | 0 .../crypto/CryptoWorkflowImpl.java | 0 .../payloadconverter/crypto/MyCustomer.java | 0 .../samples/payloadconverter/crypto/README.md | 0 .../payloadconverter/crypto/Starter.java | 0 .../peractivityoptions/FailingActivities.java | 0 .../FailingActivitiesImpl.java | 0 .../PerActivityOptionsWorkflow.java | 0 .../PerActivityOptionsWorkflowImpl.java | 0 .../samples/peractivityoptions/README.md | 0 .../samples/peractivityoptions/Starter.java | 0 .../samples/polling/PollingActivities.java | 0 .../samples/polling/PollingWorkflow.java | 0 .../io/temporal/samples/polling/README.md | 0 .../temporal/samples/polling/TestService.java | 0 .../frequent/FrequentPollingActivityImpl.java | 0 .../frequent/FrequentPollingStarter.java | 0 .../frequent/FrequentPollingWorkflowImpl.java | 0 .../samples/polling/frequent/README.md | 0 .../InfrequentPollingActivityImpl.java | 0 .../infrequent/InfrequentPollingStarter.java | 0 .../InfrequentPollingWorkflowImpl.java | 0 .../samples/polling/infrequent/README.md | 0 .../PeriodicPollingActivityImpl.java | 0 .../PeriodicPollingChildWorkflowImpl.java | 0 .../PeriodicPollingStarter.java | 0 .../PeriodicPollingWorkflowImpl.java | 0 .../PollingChildWorkflow.java | 0 .../polling/periodicsequence/README.md | 0 .../FailureRequester.java | 0 .../retryonsignalinterceptor/MyActivity.java | 0 .../MyActivityImpl.java | 0 .../retryonsignalinterceptor/MyWorkflow.java | 0 .../MyWorkflowImpl.java | 0 .../MyWorkflowWorker.java | 0 .../QueryRequester.java | 0 .../retryonsignalinterceptor/README.MD | 0 .../RetryOnSignalInterceptorListener.java | 0 .../RetryOnSignalWorkerInterceptor.java | 0 ...SignalWorkflowInboundCallsInterceptor.java | 0 ...ignalWorkflowOutboundCallsInterceptor.java | 0 .../RetryRequester.java | 0 .../samples/ssl/SslEnabledWorker.java | 0 .../samples/terminateworkflow/MyWorkflow.java | 0 .../terminateworkflow/MyWorkflowImpl.java | 0 .../samples/terminateworkflow/README.md | 0 .../samples/terminateworkflow/Starter.java | 0 .../temporal/samples/tracing/JaegerUtils.java | 0 .../io/temporal/samples/tracing/README.md | 0 .../io/temporal/samples/tracing/Starter.java | 0 .../samples/tracing/TracingWorker.java | 0 .../tracing/workflow/TracingActivities.java | 0 .../workflow/TracingActivitiesImpl.java | 0 .../workflow/TracingChildWorkflow.java | 0 .../workflow/TracingChildWorkflowImpl.java | 0 .../tracing/workflow/TracingWorkflow.java | 0 .../tracing/workflow/TracingWorkflowImpl.java | 0 .../updatabletimer/DynamicSleepWorkflow.java | 0 .../DynamicSleepWorkflowImpl.java | 0 .../DynamicSleepWorkflowStarter.java | 0 .../DynamicSleepWorkflowWorker.java | 0 .../temporal/samples/updatabletimer/README.md | 0 .../updatabletimer/UpdatableTimer.java | 0 .../updatabletimer/WakeUpTimeUpdater.java | 0 .../dsl/bankingtransactions/datainput.json | 0 .../dsl/bankingtransactions/workflow.json | 0 .../dsl/bankingtransactions/workflow.yml | 0 .../childworkflow.json | 0 .../bankingtransactionssubflow/datainput.json | 0 .../parentworkflow.json | 0 .../dsl/customerapplication/datainput.json | 0 .../dsl/customerapplication/workflow.json | 0 .../dsl/customerapplication/workflow.yml | 0 .../customerapproval/applicantdatainput.json | 0 .../customerapproval/applicantworkflow.json | 0 .../customerapproval/approvaldatainput.json | 0 .../customerapproval/approvalworkflow.json | 0 {src => core/src}/main/resources/logback.xml | 0 .../samples/asyncchild/AsyncChildTest.java | 0 ...HeartbeatingActivityBatchWorkflowTest.java | 0 .../IteratorIteratorBatchWorkflowTest.java | 0 .../SlidingWindowBatchWorkflowTest.java | 0 .../TripBookingWorkflowJUnit5Test.java | 0 .../bookingsaga/TripBookingWorkflowTest.java | 0 .../ClientCountInterceptorTest.java | 0 .../WorkerCountInterceptorTest.java | 0 .../temporal/samples/dsl/DslWorkflowTest.java | 0 .../encodefailures/EncodeFailuresTest.java | 11 +- .../fileprocessing/FileProcessingTest.java | 0 .../getresultsasync/GetResultsAsyncTest.java | 0 ...elloActivityExclusiveChoiceJUnit5Test.java | 0 .../HelloActivityExclusiveChoiceTest.java | 0 .../hello/HelloActivityJUnit5Test.java | 0 .../hello/HelloActivityReplayTest.java | 0 .../samples/hello/HelloActivityRetryTest.java | 0 .../samples/hello/HelloActivityTest.java | 0 .../HelloAsyncActivityCompletionTest.java | 0 .../samples/hello/HelloAsyncLambdaTest.java | 0 .../samples/hello/HelloAsyncTest.java | 0 .../hello/HelloCancellationScopeTest.java | 0 .../samples/hello/HelloChildJUnit5Test.java | 0 .../samples/hello/HelloChildTest.java | 0 .../temporal/samples/hello/HelloCronTest.java | 0 .../HelloDetachedCancellationScopeTest.java | 0 .../hello/HelloDynamicActivityJUnit5Test.java | 0 .../samples/hello/HelloDynamicTest.java | 0 .../samples/hello/HelloExceptionTest.java | 0 .../samples/hello/HelloLocalActivityTest.java | 0 .../hello/HelloParallelActivityTest.java | 0 .../samples/hello/HelloPeriodicTest.java | 0 .../hello/HelloPolymorphicActivityTest.java | 0 .../samples/hello/HelloQueryTest.java | 0 .../hello/HelloSearchAttributesTest.java | 0 .../samples/hello/HelloSideEffectTest.java | 0 .../samples/hello/HelloSignalTest.java | 0 .../listworkflows/ListWorkflowsTest.java | 0 .../temporal/samples/metrics/MetricsTest.java | 0 .../moneybatch/TransferWorkflowTest.java | 0 .../moneytransfer/TransferWorkflowTest.java | 0 .../CloudEventsPayloadConverterTest.java | 0 .../CryptoPayloadConverterTest.java | 0 .../PerActivityOptionsTest.java | 0 .../samples/polling/FrequentPollingTest.java | 0 .../polling/InfrequentPollingTest.java | 0 .../samples/polling/PeriodicPollingTest.java | 0 .../RetryOnSignalInterceptorTest.java | 0 .../TerminateWorkflowTest.java | 0 .../temporal/samples/tracing/TracingTest.java | 0 .../dsl/bankingtransactions/datainput.json | 0 .../dsl/bankingtransactions/workflow.json | 0 .../dsl/bankingtransactions/workflow.yml | 0 .../dsl/customerapplication/datainput.json | 0 .../dsl/customerapplication/workflow.json | 0 .../dsl/customerapplication/workflow.yml | 0 settings.gradle | 2 + springboot/build.gradle | 24 ++ .../samples/springboot/SamplesController.java | 47 ++++ .../TemporalSpringbootSamplesApplication.java | 30 +++ .../springboot/hello/HelloActivity.java | 27 +++ .../springboot/hello/HelloActivityImpl.java | 37 +++ .../springboot/hello/HelloWorkflow.java | 29 +++ .../springboot/hello/HelloWorkflowImpl.java | 39 ++++ .../samples/springboot/hello/README.md | 15 ++ .../src/main/resources/application.yaml | 26 +++ .../samples/springboot/HelloSampleTest.java | 66 ++++++ .../src/test/resources/application.yaml | 16 ++ 307 files changed, 547 insertions(+), 238 deletions(-) create mode 100644 core/build.gradle rename {src => core/src}/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/asyncchild/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/asyncchild/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/RecordLoader.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/iterator/SingleRecord.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/bookingsaga/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/bookingsaga/TripBookingSaga.java (100%) rename {src => core/src}/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/common/QueryWorkflowExecution.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/ClientCounter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/DslActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/DslWorkflowCache.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/Worker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/model/ActResult.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/model/Customer.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/model/WorkflowData.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java (100%) rename {src => core/src}/main/java/io/temporal/samples/dsl/utils/JQFilter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java (100%) rename {src => core/src}/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java (100%) rename {src => core/src}/main/java/io/temporal/samples/encodefailures/MyCustomer.java (100%) rename {src => core/src}/main/java/io/temporal/samples/encodefailures/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java (100%) rename {src => core/src}/main/java/io/temporal/samples/encodefailures/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java (100%) rename {src => core/src}/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java (100%) rename {src => core/src}/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/fileprocessing/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/fileprocessing/StoreActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/getresultsasync/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/getresultsasync/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/getresultsasync/Worker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloActivity.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloActivityRetry.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloAsync.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloAsyncLambda.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloCancellationScope.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloChild.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloCron.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloDynamic.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloException.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloLocalActivity.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloParallelActivity.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloPeriodic.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloQuery.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloSaga.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloSearchAttributes.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloSideEffect.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/HelloSignal.java (100%) rename {src => core/src}/main/java/io/temporal/samples/hello/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/listworkflows/Customer.java (100%) rename {src => core/src}/main/java/io/temporal/samples/listworkflows/CustomerActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/listworkflows/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/listworkflows/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/metrics/MetricsStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/metrics/MetricsUtils.java (100%) rename {src => core/src}/main/java/io/temporal/samples/metrics/MetricsWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/metrics/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneybatch/Account.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneybatch/AccountImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneybatch/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/moneybatch/TransferRequester.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneytransfer/Account.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneytransfer/AccountImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/moneytransfer/README.MD (100%) rename {src => core/src}/main/java/io/temporal/samples/moneytransfer/TransferRequester.java (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/cloudevents/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/crypto/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/peractivityoptions/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/peractivityoptions/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/PollingActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/PollingWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/TestService.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/frequent/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/infrequent/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/polling/periodicsequence/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java (100%) rename {src => core/src}/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java (100%) rename {src => core/src}/main/java/io/temporal/samples/ssl/SslEnabledWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/terminateworkflow/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/terminateworkflow/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/JaegerUtils.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/Starter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/TracingWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java (100%) rename {src => core/src}/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java (100%) rename {src => core/src}/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java (100%) rename {src => core/src}/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java (100%) rename {src => core/src}/main/java/io/temporal/samples/updatabletimer/README.md (100%) rename {src => core/src}/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java (100%) rename {src => core/src}/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java (100%) rename {src => core/src}/main/resources/dsl/bankingtransactions/datainput.json (100%) rename {src => core/src}/main/resources/dsl/bankingtransactions/workflow.json (100%) rename {src => core/src}/main/resources/dsl/bankingtransactions/workflow.yml (100%) rename {src => core/src}/main/resources/dsl/bankingtransactionssubflow/childworkflow.json (100%) rename {src => core/src}/main/resources/dsl/bankingtransactionssubflow/datainput.json (100%) rename {src => core/src}/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json (100%) rename {src => core/src}/main/resources/dsl/customerapplication/datainput.json (100%) rename {src => core/src}/main/resources/dsl/customerapplication/workflow.json (100%) rename {src => core/src}/main/resources/dsl/customerapplication/workflow.yml (100%) rename {src => core/src}/main/resources/dsl/customerapproval/applicantdatainput.json (100%) rename {src => core/src}/main/resources/dsl/customerapproval/applicantworkflow.json (100%) rename {src => core/src}/main/resources/dsl/customerapproval/approvaldatainput.json (100%) rename {src => core/src}/main/resources/dsl/customerapproval/approvalworkflow.json (100%) rename {src => core/src}/main/resources/logback.xml (100%) rename {src => core/src}/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowJUnit5Test.java (100%) rename {src => core/src}/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/dsl/DslWorkflowTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java (93%) rename {src => core/src}/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloActivityTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloAsyncTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloChildTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloCronTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloDynamicTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloExceptionTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloPeriodicTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloQueryTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloSideEffectTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/hello/HelloSignalTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/metrics/MetricsTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/polling/FrequentPollingTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/polling/InfrequentPollingTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/polling/PeriodicPollingTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java (100%) rename {src => core/src}/test/java/io/temporal/samples/tracing/TracingTest.java (100%) rename {src => core/src}/test/resources/dsl/bankingtransactions/datainput.json (100%) rename {src => core/src}/test/resources/dsl/bankingtransactions/workflow.json (100%) rename {src => core/src}/test/resources/dsl/bankingtransactions/workflow.yml (100%) rename {src => core/src}/test/resources/dsl/customerapplication/datainput.json (100%) rename {src => core/src}/test/resources/dsl/customerapplication/workflow.json (100%) rename {src => core/src}/test/resources/dsl/customerapplication/workflow.yml (100%) create mode 100644 springboot/build.gradle create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/hello/README.md create mode 100644 springboot/src/main/resources/application.yaml create mode 100644 springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java create mode 100644 springboot/src/test/resources/application.yaml diff --git a/.gitignore b/.gitignore index 1ffd0e5f1..5b96932e2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,11 @@ target .idea .gradle /build +/core/build +/springboot/build /out +/core/out +/springboot/out .classpath .project .settings/ diff --git a/README.md b/README.md index 4d94e6942..00ed6f992 100644 --- a/README.md +++ b/README.md @@ -1,192 +1,132 @@ # Temporal Java SDK Samples -This repository contains sample Workflow applications that demonstrate various capabilities of Temporal using the [Java SDK](https://github.com/temporalio/sdk-java). - -- Temporal Server repo: https://github.com/temporalio/temporal -- Temporal Java SDK repo: https://github.com/temporalio/sdk-java -- Java SDK docs: https://docs.temporal.io/docs/java/introduction/ - -## Table of Contents - -- [Temporal Java SDK Samples](#temporal-java-sdk-samples) - - [Table of Contents](#table-of-contents) - - [How to use](#how-to-use) - - [Temporal Web UI](#temporal-web-ui) - - [Running samples](#running-samples) - - [Samples directory](#samples-directory) - - [Hello samples](#hello-samples) - - [Scenario-based samples](#scenario-based-samples) - - [API demonstrations](#api-demonstrations) - - [SDK Metrics](#sdk-metrics) - - [Tracing Support](#tracing-support) - - [IDE Integration](#ide-integration) - - [IntelliJ](#intellij) +This repository contains samples that demonstrate various capabilities of +Temporal using the [Java SDK](https://github.com/temporalio/sdk-java). + +It contains two modules: +* [Core](/core): showcases many different SDK features. +* [SpringBoot](/springboot): showcases springboot autoconfig integration. + +## Learn more about Temporal and Java SDK + +- [Temporal Server repo](https://github.com/temporalio/temporal) +- [Java SDK repo](https://github.com/temporalio/sdk-java) +- [Java SDK Guide](https://docs.temporal.io/dev-guide/java) ## Requirements - Java 1.8+ for build and runtime - Java 11+ for development and contribution +- Local Temporal Server, easiest to get started would be using [Temporal CLI](https://github.com/temporalio/cli). +For more options see docs [here](https://docs.temporal.io/kb/all-the-ways-to-run-a-cluster). -## How to use + +## Build and run tests 1. Clone this repository: git clone https://github.com/temporalio/samples-java cd samples-java -2. Build the examples and run tests: +2. Build and run Tests ./gradlew build -3. You need a locally running Temporal Server instance to run the samples. We recommend a locally running - version of the Temporal Server managed via [Docker Compose](https://docs.docker.com/compose/gettingstarted/): - - git clone https://github.com/temporalio/docker-compose.git - cd docker-compose - docker-compose up - -Note that for the "listworkflows" example you need to have the Elasticsearch feature -enabled on the Temporal Server side. To do this you can run locally with: - - git clone https://github.com/temporalio/docker-compose.git - cd docker-compose - docker-compose -f docker-compose-cass-es.yml up - -Alternatively you could install the Temporal Server on Kubernetes / Minicube using the [Temporal Helm charts](https://github.com/temporalio/helm-charts). -Note that in this case you should use the [Temporal CLI (tctl)](https://docs.temporal.io/tctl-v1) tool to create a namespace called "default": - - tctl --ns default n re - -## Temporal Web UI - -The Temporal Server running in a docker container includes a Web UI, exposed by default on port 8080 of the docker host. -If you are running Docker on your host, you can connect to the WebUI running using a browser and opening the following URI: - -[http://localhost:8080](http://localhost:8080) +## Running Samples: -If you are running Docker on a different host (e.g.: a virtual machine), then modify the URI accordingly by specifying the correct host and the correct port. +You can run both "Core" and "SpringBoot" samples from the main samples project directory. +Details on how to run each sample can be found in following two sections. +To skip to SpringBoot samples click [here](#Running-SpringBoot-Samples). -[http://${DOCKER_HOST}:${WEBUI_PORT}](http://${DOCKER_HOST}:${WEBUI_PORT}). - -If you have deployed the Temporal Server on Kubernetes using Helm Charts, you can use the kubectl command-line tool -to forward your local machine ports to the Temporal Web UI: - - kubectl port-forward services/temporaltest-web 8088:8088 - kubectl port-forward services/temporaltest-frontend-headless 7233:7233 - -With this you should be able to access the Temporal Web UI with [http://localhost:8088](http://localhost:8088). - -## Running samples - -By default, samples assume relevant Temporal container ports are listening on `localhost`, on port `7233`. -If this is not the case, you can tunnel traffic to this port to a different one (even running on a different host), using for example `netcat`, `socat`, or `ssh`. - -If, for example, you're running Docker on a virtual machine `vm`, you can use `ssh` to tunnel the traffic using the following command before running the samples: - -``` -ssh -g -L 7233:localhost:7233 -N user@vm -``` - -## Samples directory - -The following section lists all available samples. -Click on the sample link to view the README, which contains instructions on how to run them. - -Each sample has an associated unit test which demonstrates the use of the Temporal Java SDK testing API. -All tests are available under [src/test/java](./src/test/java/io/temporal/samples) +### Running "Core" samples +See the README.md file in each main sample directory for cut/paste Gradle command to run specific example. -### Hello samples +#### Hello samples -- [**Hello**](./src/main/java/io/temporal/samples/hello): This sample includes a number of individual Workflows that can be executed independently. Each one demonstrates something specific. - - [**HelloActivity**](./src/main/java/io/temporal/samples/hello/HelloActivity.java): Demonstrates a Workflow Definition that executes a single Activity. - - [**HelloActivityRetry**](./src/main/java/io/temporal/samples/hello/HelloActivityRetry.java): Demonstrates how to Retry an Activity Execution. - - [**HelloActivityExclusiveChoice**](./src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java): Demonstrates how to execute Activities based on dynamic input. - - [**HelloAsync**](./src/main/java/io/temporal/samples/hello/HelloAsync.java): Demonstrates how to execute Activities asynchronously and wait for them using Promises. - - [**HelloParallelActivity**](./src/main/java/io/temporal/samples/hello/HelloParallelActivity.java): Demonstrates how to execute multiple Activities in parallel, asynchronously, and wait for them using `Promise.allOf`. - - [**HelloAsyncActivityCompletion**](./src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java): Demonstrates how to complete an Activity Execution asynchronously. - - [**HelloAsyncLambda**](./src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java): Demonstrates how to execute part of a Workflow asynchronously in a separate task (thread). - - [**HelloCancellationScope**](./src/main/java/io/temporal/samples/hello/HelloCancellationScope.java): Demonstrates how to explicitly cancel parts of a Workflow Execution. - - [**HelloDetachedCancellationScope**](./src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java): Demonstrates how to execute cleanup code after a Workflow Execution has been explicitly cancelled. - - [**HelloChild**](./src/main/java/io/temporal/samples/hello/HelloChild.java): Demonstrates how to execute a simple Child Workflow. - - [**HelloCron**](./src/main/java/io/temporal/samples/hello/HelloCron.java): Demonstrates how to execute a Workflow according to a cron schedule. - - [**HelloDynamic**](./src/main/java/io/temporal/samples/hello/HelloDynamic.java): Demonstrates how to use `DynamicWorkflow` and `DynamicActivity` interfaces. - - [**HelloPeriodic**](./src/main/java/io/temporal/samples/hello/HelloPeriodic.java): Demonstrates the use of the Continue-As-New feature. - - [**HelloException**](./src/main/java/io/temporal/samples/hello/HelloException.java): Demonstrates how to handle exception propagation and wrapping. - - [**HelloLocalActivity**](./src/main/java/io/temporal/samples/hello/HelloLocalActivity.java): Demonstrates the use of a [Local Activity](https://docs.temporal.io/docs/jargon/mesh/#local-activity). - - [**HelloPolymorphicActivity**](./src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java): Demonstrates Activity Definitions that extend a common interface. - - [**HelloQuery**](./src/main/java/io/temporal/samples/hello/HelloQuery.java): Demonstrates how to Query the state of a Workflow Execution. - - [**HelloSignal**](./src/main/java/io/temporal/samples/hello/HelloSignal.java): Demonstrates how to send and handle a Signal. - - [**HelloSaga**](./src/main/java/io/temporal/samples/hello/HelloSaga.java): Demonstrates how to use the SAGA feature. - - [**HelloSearchAttributes**](./src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java): Demonstrates how to add custom Search Attributes to Workflow Executions. - - [**HelloSideEffect**](./src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. +- [**Hello**](/core/src/main/java/io/temporal/samples/hello): This sample includes a number of individual Workflows that can be executed independently. Each one demonstrates something specific. + - [**HelloActivity**](/core/src/main/java/io/temporal/samples/hello/HelloActivity.java): Demonstrates a Workflow Definition that executes a single Activity. + - [**HelloActivityRetry**](/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java): Demonstrates how to Retry an Activity Execution. + - [**HelloActivityExclusiveChoice**](/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java): Demonstrates how to execute Activities based on dynamic input. + - [**HelloAsync**](/core/src/main/java/io/temporal/samples/hello/HelloAsync.java): Demonstrates how to execute Activities asynchronously and wait for them using Promises. + - [**HelloParallelActivity**](/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java): Demonstrates how to execute multiple Activities in parallel, asynchronously, and wait for them using `Promise.allOf`. + - [**HelloAsyncActivityCompletion**](/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java): Demonstrates how to complete an Activity Execution asynchronously. + - [**HelloAsyncLambda**](/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java): Demonstrates how to execute part of a Workflow asynchronously in a separate task (thread). + - [**HelloCancellationScope**](/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java): Demonstrates how to explicitly cancel parts of a Workflow Execution. + - [**HelloDetachedCancellationScope**](/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java): Demonstrates how to execute cleanup code after a Workflow Execution has been explicitly cancelled. + - [**HelloChild**](/core/src/main/java/io/temporal/samples/hello/HelloChild.java): Demonstrates how to execute a simple Child Workflow. + - [**HelloCron**](/core/src/main/java/io/temporal/samples/hello/HelloCron.java): Demonstrates how to execute a Workflow according to a cron schedule. + - [**HelloDynamic**](/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java): Demonstrates how to use `DynamicWorkflow` and `DynamicActivity` interfaces. + - [**HelloPeriodic**](/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java): Demonstrates the use of the Continue-As-New feature. + - [**HelloException**](/core/src/main/java/io/temporal/samples/hello/HelloException.java): Demonstrates how to handle exception propagation and wrapping. + - [**HelloLocalActivity**](/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java): Demonstrates the use of a [Local Activity](https://docs.temporal.io/docs/jargon/mesh/#local-activity). + - [**HelloPolymorphicActivity**](/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java): Demonstrates Activity Definitions that extend a common interface. + - [**HelloQuery**](/core/src/main/java/io/temporal/samples/hello/HelloQuery.java): Demonstrates how to Query the state of a Workflow Execution. + - [**HelloSignal**](/core/src/main/java/io/temporal/samples/hello/HelloSignal.java): Demonstrates how to send and handle a Signal. + - [**HelloSaga**](/core/src/main/java/io/temporal/samples/hello/HelloSaga.java): Demonstrates how to use the SAGA feature. + - [**HelloSearchAttributes**](/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java): Demonstrates how to add custom Search Attributes to Workflow Executions. + - [**HelloSideEffect**](/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. -### Scenario-based samples +#### Scenario-based samples -- [**File Processing Sample**](./src/main/java/io/temporal/samples/fileprocessing): Demonstrates how to route tasks to specific Workers. This sample has a set of Activities that download a file, processes it, and uploads the result to a destination. Any Worker can execute the first Activity. However, the second and third Activities must be executed on the same host as the first one. +- [**File Processing Sample**](/core/src/main/java/io/temporal/samples/fileprocessing): Demonstrates how to route tasks to specific Workers. This sample has a set of Activities that download a file, processes it, and uploads the result to a destination. Any Worker can execute the first Activity. However, the second and third Activities must be executed on the same host as the first one. -- [**Booking SAGA**](./src/main/java/io/temporal/samples/bookingsaga): Demonstrates Temporals take on the Camunda BPMN "trip booking" example. +- [**Booking SAGA**](/core/src/main/java/io/temporal/samples/bookingsaga): Demonstrates Temporals take on the Camunda BPMN "trip booking" example. -- [**Money Transfer**](./src/main/java/io/temporal/samples/moneytransfer): Demonstrates the use of a dedicated Activity Worker. +- [**Money Transfer**](/core/src/main/java/io/temporal/samples/moneytransfer): Demonstrates the use of a dedicated Activity Worker. -- [**Money Batch**](./src/main/java/io/temporal/samples/moneybatch): Demonstrates a situation where a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. This sample can be easily extended to perform a payment based on more complex criteria, such as at a specific time or an accumulated amount. The sample also demonstrates how to Signal the Workflow when it executes (*Signal with start*). If the Workflow is already executing, it just receives the Signal. If it is not executing, then the Workflow executes first, and then the Signal is delivered to it. *Signal with start* is a "lazy" way to execute Workflows when Signaling them. +- [**Money Batch**](/core/src/main/java/io/temporal/samples/moneybatch): Demonstrates a situation where a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. This sample can be easily extended to perform a payment based on more complex criteria, such as at a specific time or an accumulated amount. The sample also demonstrates how to Signal the Workflow when it executes (*Signal with start*). If the Workflow is already executing, it just receives the Signal. If it is not executing, then the Workflow executes first, and then the Signal is delivered to it. *Signal with start* is a "lazy" way to execute Workflows when Signaling them. -- [**Customer Application Approval DSL**](./src/main/java/io/temporal/samples/dsl): Demonstrates execution of a customer application approval workflow defined in a DSL (like JSON or YAML) +- [**Customer Application Approval DSL**](/core/src/main/java/io/temporal/samples/dsl): Demonstrates execution of a customer application approval workflow defined in a DSL (like JSON or YAML) -- [**Polling Services**](./src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion +- [**Polling Services**](/core/src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion -- [**Heartbeating Activity Batch**](./src/main/java/io/temporal/samples/batch/heartbeatingactivity): Batch job implementation using a heartbeating activity. +- [**Heartbeating Activity Batch**](/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity): Batch job implementation using a heartbeating activity. -- [**Iterator Batch**](./src/main/java/io/temporal/samples/batch/iterator): Batch job implementation using the workflow iterator pattern. +- [**Iterator Batch**](/core/src/main/java/io/temporal/samples/batch/iterator): Batch job implementation using the workflow iterator pattern. -- [**Sliding Window Batch**](./src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. +- [**Sliding Window Batch**](/core/src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. -### API demonstrations +#### API demonstrations -- [**Updatable Timer**](./src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. +- [**Updatable Timer**](/core/src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. -- [**Workflow Count Interceptor**](./src/main/java/io/temporal/samples/countinterceptor): Demonstrates how to create and register a simple Workflow Count Interceptor. -- -- [**Workflow Retry On Signal Interceptor**](./src/main/java/io/temporal/samples/retryonsignalinterceptor): Demonstrates how to create and register an interceptor that retries an activity on a signal. +- [**Workflow Count Interceptor**](/core/src/main/java/io/temporal/samples/countinterceptor): Demonstrates how to create and register a simple Workflow Count Interceptor. +- +- [**Workflow Retry On Signal Interceptor**](/core/src/main/java/io/temporal/samples/retryonsignalinterceptor): Demonstrates how to create and register an interceptor that retries an activity on a signal. -- [**List Workflows**](./src/main/java/io/temporal/samples/listworkflows): Demonstrates the use of custom search attributes and ListWorkflowExecutionsRequest with custom queries. +- [**List Workflows**](/core/src/main/java/io/temporal/samples/listworkflows): Demonstrates the use of custom search attributes and ListWorkflowExecutionsRequest with custom queries. -- [**Payload Converter - CloudEvents**](./src/main/java/io/temporal/samples/payloadconverter/cloudevents): Demonstrates the use of a custom payload converter for CloudEvents. +- [**Payload Converter - CloudEvents**](/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents): Demonstrates the use of a custom payload converter for CloudEvents. -- [**Payload Converter - Crypto**](./src/main/java/io/temporal/samples/payloadconverter/crypto): Demonstrates the use of a custom payload converter using jackson-json-crypto. +- [**Payload Converter - Crypto**](/core/src/main/java/io/temporal/samples/payloadconverter/crypto): Demonstrates the use of a custom payload converter using jackson-json-crypto. -- [**Async Child Workflow**](./src/main/java/io/temporal/samples/asyncchild): Demonstrates how to invoke a child workflow async, that can complete after parent workflow is already completed. +- [**Async Child Workflow**](/core/src/main/java/io/temporal/samples/asyncchild): Demonstrates how to invoke a child workflow async, that can complete after parent workflow is already completed. -- [**Terminate Workflow**](./src/main/java/io/temporal/samples/terminateworkflow): Demonstrates how to terminate a workflow using client API. +- [**Terminate Workflow**](/core/src/main/java/io/temporal/samples/terminateworkflow): Demonstrates how to terminate a workflow using client API. -- [**Get Workflow Results Async**](./src/main/java/io/temporal/samples/getresultsasync): Demonstrates how to start and get workflow results in async manner. +- [**Get Workflow Results Async**](/core/src/main/java/io/temporal/samples/getresultsasync): Demonstrates how to start and get workflow results in async manner. -- [**Per Activity Type Options**](./src/main/java/io/temporal/samples/peractivityoptions): Demonstrates how to set per Activity type options. +- [**Per Activity Type Options**](/core/src/main/java/io/temporal/samples/peractivityoptions): Demonstrates how to set per Activity type options. -- [**Configure WorkflowClient to use mTLS**](./src/main/java/io/temporal/samples/ssl): Demonstrates how to configure WorkflowClient when using mTLS. +- [**Configure WorkflowClient to use mTLS**](/core/src/main/java/io/temporal/samples/ssl): Demonstrates how to configure WorkflowClient when using mTLS. -- [**Payload Codec**](./src/main/java/io/temporal/samples/encodefailures): Demonstrates how to use simple codec to encode/decode failure messages. +- [**Payload Codec**](/core/src/main/java/io/temporal/samples/encodefailures): Demonstrates how to use simple codec to encode/decode failure messages. -### SDK Metrics +#### SDK Metrics -- [**Set up SDK metrics**](./src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics. +- [**Set up SDK metrics**](/core/src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics. -### Tracing Support +#### Tracing Support -- [**Set up OpenTracing and/or OpenTelemetry with Jaeger**](./src/main/java/io/temporal/samples/tracing): Demonstrates how to set up OpenTracing and/or OpenTelemetry and view traces using Jaeger. +- [**Set up OpenTracing and/or OpenTelemetry with Jaeger**](/core/src/main/java/io/temporal/samples/tracing): Demonstrates how to set up OpenTracing and/or OpenTelemetry and view traces using Jaeger. -## IDE Integration - -### IntelliJ - -It is possible to run the samples from the command line, but if you prefer IntelliJ here are the import steps: +### Running SpringBoot Samples +See the README.md file in each main sample directory for cut/paste Gradle command to run specific example. -* Navigate to **File**->**New**->**Project from Existing Sources**. -* Select the cloned directory. -* In the **Import Project page**, select **Import project from external model** -* Choose **Gradle** and then click **Next** -* Click **Finish**. +- [**Hello**](/springboot/src/main/java/io/temporal/samples/springboot/hello): Invoke simple "Hello" workflow from a GET endpoint + diff --git a/build.gradle b/build.gradle index 64d7dae4c..8dfd51515 100644 --- a/build.gradle +++ b/build.gradle @@ -1,113 +1,61 @@ -// Run 'gradle checkUpdates' to find out which dependencies have newer versions - plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.1.0" id 'com.diffplug.spotless' version '6.17.0' apply false + id 'org.springframework.boot' version '2.7.12' } -apply plugin: 'java' - -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} +subprojects { + apply plugin: 'java' + apply plugin: 'org.cadixdev.licenser' + apply plugin: 'net.ltgt.errorprone' + apply plugin: 'com.diffplug.spotless' -repositories { - maven { - url "https://oss.sonatype.org/content/repositories/snapshots/" + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + ext { + otelVersion = '1.26.0' + otelVersionAlpha = "${otelVersion}-alpha" + javaSDKVersion = '1.19.1' + jarVersion = '1.0.0' } - mavenCentral() -} - -ext { - otelVersion = '1.26.0' - otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.19.1' -} - -dependencies { - // Temporal SDK - implementation "io.temporal:temporal-sdk:$javaSDKVersion" - implementation "io.temporal:temporal-opentracing:$javaSDKVersion" - testImplementation("io.temporal:temporal-testing:$javaSDKVersion") - - // Needed for SDK related functionality - implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.2")) - implementation "com.fasterxml.jackson.core:jackson-databind" - implementation "com.fasterxml.jackson.core:jackson-core" - - implementation "io.micrometer:micrometer-registry-prometheus" - - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.7' - implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' - - implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) - implementation "io.opentelemetry:opentelemetry-sdk" - implementation "io.opentelemetry:opentelemetry-exporter-jaeger" - implementation "io.opentelemetry:opentelemetry-extension-trace-propagators" - implementation "io.opentelemetry:opentelemetry-opentracing-shim:$otelVersionAlpha" - implementation "io.opentelemetry:opentelemetry-semconv:$otelVersionAlpha" - implementation 'io.jaegertracing:jaeger-client:1.8.1' - - // Used in samples - implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' - implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' - implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.2' - implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.2' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.3.Final' - implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20220705' - - // we don't update it to 2.1.0 because 2.1.0 requires Java 11 - implementation 'com.codingrodent:jackson-json-crypto:1.1.0' - - testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.3.1" - - testImplementation(platform("org.junit:junit-bom:5.9.3")) - testImplementation "org.junit.jupiter:junit-jupiter-api" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" - testRuntimeOnly "org.junit.vintage:junit-vintage-engine" - dependencies { - errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.18.0') - } else { - errorprone('com.google.errorprone:error_prone_core:2.18.0') + repositories { + maven { + url "https://oss.sonatype.org/content/repositories/snapshots/" } + mavenCentral() } -} -task execute(type: JavaExec) { - mainClass = findProperty("mainClass") ?: "" - classpath = sourceSets.main.runtimeClasspath -} + dependencies { -test { - useJUnitPlatform() -} + } -license { - header rootProject.file('license-header.txt') - exclude '**/*.json' - exclude '**/*.yml' -} + license { + header rootProject.file('license-header.txt') + exclude '**/*.json' + exclude '**/*.yaml' + exclude '**/*.yml' + } -if (JavaVersion.current().isJava11Compatible()) { - // Code should be formatted using the latest googleJavaFormat, but it doesn't support Java <11 since version 1.8 - apply plugin: 'com.diffplug.spotless' + if (JavaVersion.current().isJava11Compatible()) { + // Code should be formatted using the latest googleJavaFormat, but it doesn't support Java <11 since version 1.8 + apply plugin: 'com.diffplug.spotless' - spotless { - java { - target 'src/*/java/**/*.java' - targetExclude '**/.idea/**' - googleJavaFormat('1.16.0') + spotless { + java { + target 'src/*/java/**/*.java' + targetExclude '**/.idea/**' + googleJavaFormat('1.16.0') + } } + + compileJava.dependsOn 'spotlessApply' } - compileJava.dependsOn 'spotlessApply' -} + test { + useJUnitPlatform() + } +} \ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle new file mode 100644 index 000000000..ae9bd0255 --- /dev/null +++ b/core/build.gradle @@ -0,0 +1,60 @@ +dependencies { + // Temporal SDK + implementation "io.temporal:temporal-sdk:$javaSDKVersion" + implementation "io.temporal:temporal-opentracing:$javaSDKVersion" + testImplementation("io.temporal:temporal-testing:$javaSDKVersion") + + // Needed for SDK related functionality + implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.2")) + implementation "com.fasterxml.jackson.core:jackson-databind" + implementation "com.fasterxml.jackson.core:jackson-core" + + implementation "io.micrometer:micrometer-registry-prometheus" + + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.7' + implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' + + implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) + implementation "io.opentelemetry:opentelemetry-sdk" + implementation "io.opentelemetry:opentelemetry-exporter-jaeger" + implementation "io.opentelemetry:opentelemetry-extension-trace-propagators" + implementation "io.opentelemetry:opentelemetry-opentracing-shim:$otelVersionAlpha" + implementation "io.opentelemetry:opentelemetry-semconv:$otelVersionAlpha" + implementation 'io.jaegertracing:jaeger-client:1.8.1' + + // Used in samples + implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' + implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' + implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.2' + implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.2' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.3.Final' + implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20220705' + + // we don't update it to 2.1.0 because 2.1.0 requires Java 11 + implementation 'com.codingrodent:jackson-json-crypto:1.1.0' + + testImplementation "junit:junit:4.13.2" + testImplementation "org.mockito:mockito-core:5.3.1" + + testImplementation(platform("org.junit:junit-bom:5.9.3")) + testImplementation "org.junit.jupiter:junit-jupiter-api" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" + testRuntimeOnly "org.junit.vintage:junit-vintage-engine" + + dependencies { + errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') + if (JavaVersion.current().isJava11Compatible()) { + errorprone('com.google.errorprone:error_prone_core:2.18.0') + } else { + errorprone('com.google.errorprone:error_prone_core:2.18.0') + } + } +} + +task execute(type: JavaExec) { + mainClass = findProperty("mainClass") ?: "" + classpath = sourceSets.main.runtimeClasspath +} diff --git a/src/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java b/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java rename to core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java diff --git a/src/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java b/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java rename to core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java diff --git a/src/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java b/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/asyncchild/README.md b/core/src/main/java/io/temporal/samples/asyncchild/README.md similarity index 100% rename from src/main/java/io/temporal/samples/asyncchild/README.md rename to core/src/main/java/io/temporal/samples/asyncchild/README.md diff --git a/src/main/java/io/temporal/samples/asyncchild/Starter.java b/core/src/main/java/io/temporal/samples/asyncchild/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/asyncchild/Starter.java rename to core/src/main/java/io/temporal/samples/asyncchild/Starter.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java diff --git a/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java rename to core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java rename to core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java rename to core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java rename to core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/README.md b/core/src/main/java/io/temporal/samples/batch/iterator/README.md similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/README.md rename to core/src/main/java/io/temporal/samples/batch/iterator/README.md diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java b/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java rename to core/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java b/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java rename to core/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java b/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java rename to core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java b/core/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java rename to core/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/README.md b/core/src/main/java/io/temporal/samples/batch/slidingwindow/README.md similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/README.md rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/README.md diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java diff --git a/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/bookingsaga/README.md b/core/src/main/java/io/temporal/samples/bookingsaga/README.md similarity index 100% rename from src/main/java/io/temporal/samples/bookingsaga/README.md rename to core/src/main/java/io/temporal/samples/bookingsaga/README.md diff --git a/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java rename to core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java diff --git a/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java rename to core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java diff --git a/src/main/java/io/temporal/samples/bookingsaga/TripBookingSaga.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingSaga.java similarity index 100% rename from src/main/java/io/temporal/samples/bookingsaga/TripBookingSaga.java rename to core/src/main/java/io/temporal/samples/bookingsaga/TripBookingSaga.java diff --git a/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java rename to core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java diff --git a/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java b/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java similarity index 100% rename from src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java rename to core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java b/core/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java rename to core/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java b/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java rename to core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/README.md b/core/src/main/java/io/temporal/samples/countinterceptor/README.md similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/README.md rename to core/src/main/java/io/temporal/samples/countinterceptor/README.md diff --git a/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java rename to core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java rename to core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java rename to core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java rename to core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java rename to core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java rename to core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java b/core/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java rename to core/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java b/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java rename to core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java b/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java rename to core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java rename to core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java rename to core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java diff --git a/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/dsl/DslActivities.java b/core/src/main/java/io/temporal/samples/dsl/DslActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/DslActivities.java rename to core/src/main/java/io/temporal/samples/dsl/DslActivities.java diff --git a/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java b/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java rename to core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java diff --git a/src/main/java/io/temporal/samples/dsl/DslWorkflowCache.java b/core/src/main/java/io/temporal/samples/dsl/DslWorkflowCache.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/DslWorkflowCache.java rename to core/src/main/java/io/temporal/samples/dsl/DslWorkflowCache.java diff --git a/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java b/core/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java rename to core/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java diff --git a/src/main/java/io/temporal/samples/dsl/README.md b/core/src/main/java/io/temporal/samples/dsl/README.md similarity index 100% rename from src/main/java/io/temporal/samples/dsl/README.md rename to core/src/main/java/io/temporal/samples/dsl/README.md diff --git a/src/main/java/io/temporal/samples/dsl/Starter.java b/core/src/main/java/io/temporal/samples/dsl/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/Starter.java rename to core/src/main/java/io/temporal/samples/dsl/Starter.java diff --git a/src/main/java/io/temporal/samples/dsl/Worker.java b/core/src/main/java/io/temporal/samples/dsl/Worker.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/Worker.java rename to core/src/main/java/io/temporal/samples/dsl/Worker.java diff --git a/src/main/java/io/temporal/samples/dsl/model/ActResult.java b/core/src/main/java/io/temporal/samples/dsl/model/ActResult.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/model/ActResult.java rename to core/src/main/java/io/temporal/samples/dsl/model/ActResult.java diff --git a/src/main/java/io/temporal/samples/dsl/model/Customer.java b/core/src/main/java/io/temporal/samples/dsl/model/Customer.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/model/Customer.java rename to core/src/main/java/io/temporal/samples/dsl/model/Customer.java diff --git a/src/main/java/io/temporal/samples/dsl/model/WorkflowData.java b/core/src/main/java/io/temporal/samples/dsl/model/WorkflowData.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/model/WorkflowData.java rename to core/src/main/java/io/temporal/samples/dsl/model/WorkflowData.java diff --git a/src/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java b/core/src/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java rename to core/src/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java diff --git a/src/main/java/io/temporal/samples/dsl/utils/JQFilter.java b/core/src/main/java/io/temporal/samples/dsl/utils/JQFilter.java similarity index 100% rename from src/main/java/io/temporal/samples/dsl/utils/JQFilter.java rename to core/src/main/java/io/temporal/samples/dsl/utils/JQFilter.java diff --git a/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java b/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java similarity index 100% rename from src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java rename to core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java diff --git a/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java b/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java rename to core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java diff --git a/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java b/core/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java similarity index 100% rename from src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java rename to core/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java diff --git a/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java b/core/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java similarity index 100% rename from src/main/java/io/temporal/samples/encodefailures/MyCustomer.java rename to core/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java diff --git a/src/main/java/io/temporal/samples/encodefailures/README.md b/core/src/main/java/io/temporal/samples/encodefailures/README.md similarity index 100% rename from src/main/java/io/temporal/samples/encodefailures/README.md rename to core/src/main/java/io/temporal/samples/encodefailures/README.md diff --git a/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java b/core/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java similarity index 100% rename from src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java rename to core/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java diff --git a/src/main/java/io/temporal/samples/encodefailures/Starter.java b/core/src/main/java/io/temporal/samples/encodefailures/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/encodefailures/Starter.java rename to core/src/main/java/io/temporal/samples/encodefailures/Starter.java diff --git a/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java b/core/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java similarity index 100% rename from src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java rename to core/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java diff --git a/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java b/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java similarity index 100% rename from src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java rename to core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java diff --git a/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java rename to core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java diff --git a/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java rename to core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java diff --git a/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java rename to core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java diff --git a/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/fileprocessing/README.md b/core/src/main/java/io/temporal/samples/fileprocessing/README.md similarity index 100% rename from src/main/java/io/temporal/samples/fileprocessing/README.md rename to core/src/main/java/io/temporal/samples/fileprocessing/README.md diff --git a/src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java b/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java rename to core/src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java diff --git a/src/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java b/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java rename to core/src/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java diff --git a/src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java b/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java rename to core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java diff --git a/src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/getresultsasync/README.md b/core/src/main/java/io/temporal/samples/getresultsasync/README.md similarity index 100% rename from src/main/java/io/temporal/samples/getresultsasync/README.md rename to core/src/main/java/io/temporal/samples/getresultsasync/README.md diff --git a/src/main/java/io/temporal/samples/getresultsasync/Starter.java b/core/src/main/java/io/temporal/samples/getresultsasync/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/getresultsasync/Starter.java rename to core/src/main/java/io/temporal/samples/getresultsasync/Starter.java diff --git a/src/main/java/io/temporal/samples/getresultsasync/Worker.java b/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java similarity index 100% rename from src/main/java/io/temporal/samples/getresultsasync/Worker.java rename to core/src/main/java/io/temporal/samples/getresultsasync/Worker.java diff --git a/src/main/java/io/temporal/samples/hello/HelloActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloActivity.java rename to core/src/main/java/io/temporal/samples/hello/HelloActivity.java diff --git a/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java rename to core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java diff --git a/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloActivityRetry.java rename to core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java diff --git a/src/main/java/io/temporal/samples/hello/HelloAsync.java b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloAsync.java rename to core/src/main/java/io/temporal/samples/hello/HelloAsync.java diff --git a/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java rename to core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java diff --git a/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java rename to core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java diff --git a/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloCancellationScope.java rename to core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java diff --git a/src/main/java/io/temporal/samples/hello/HelloChild.java b/core/src/main/java/io/temporal/samples/hello/HelloChild.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloChild.java rename to core/src/main/java/io/temporal/samples/hello/HelloChild.java diff --git a/src/main/java/io/temporal/samples/hello/HelloCron.java b/core/src/main/java/io/temporal/samples/hello/HelloCron.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloCron.java rename to core/src/main/java/io/temporal/samples/hello/HelloCron.java diff --git a/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java rename to core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java diff --git a/src/main/java/io/temporal/samples/hello/HelloDynamic.java b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloDynamic.java rename to core/src/main/java/io/temporal/samples/hello/HelloDynamic.java diff --git a/src/main/java/io/temporal/samples/hello/HelloException.java b/core/src/main/java/io/temporal/samples/hello/HelloException.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloException.java rename to core/src/main/java/io/temporal/samples/hello/HelloException.java diff --git a/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloLocalActivity.java rename to core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java diff --git a/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloParallelActivity.java rename to core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java diff --git a/src/main/java/io/temporal/samples/hello/HelloPeriodic.java b/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloPeriodic.java rename to core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java diff --git a/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java rename to core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java diff --git a/src/main/java/io/temporal/samples/hello/HelloQuery.java b/core/src/main/java/io/temporal/samples/hello/HelloQuery.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloQuery.java rename to core/src/main/java/io/temporal/samples/hello/HelloQuery.java diff --git a/src/main/java/io/temporal/samples/hello/HelloSaga.java b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloSaga.java rename to core/src/main/java/io/temporal/samples/hello/HelloSaga.java diff --git a/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java rename to core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java diff --git a/src/main/java/io/temporal/samples/hello/HelloSideEffect.java b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloSideEffect.java rename to core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java diff --git a/src/main/java/io/temporal/samples/hello/HelloSignal.java b/core/src/main/java/io/temporal/samples/hello/HelloSignal.java similarity index 100% rename from src/main/java/io/temporal/samples/hello/HelloSignal.java rename to core/src/main/java/io/temporal/samples/hello/HelloSignal.java diff --git a/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md similarity index 100% rename from src/main/java/io/temporal/samples/hello/README.md rename to core/src/main/java/io/temporal/samples/hello/README.md diff --git a/src/main/java/io/temporal/samples/listworkflows/Customer.java b/core/src/main/java/io/temporal/samples/listworkflows/Customer.java similarity index 100% rename from src/main/java/io/temporal/samples/listworkflows/Customer.java rename to core/src/main/java/io/temporal/samples/listworkflows/Customer.java diff --git a/src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java b/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java rename to core/src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java diff --git a/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java b/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java rename to core/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java diff --git a/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java b/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java rename to core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java diff --git a/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/listworkflows/README.md b/core/src/main/java/io/temporal/samples/listworkflows/README.md similarity index 100% rename from src/main/java/io/temporal/samples/listworkflows/README.md rename to core/src/main/java/io/temporal/samples/listworkflows/README.md diff --git a/src/main/java/io/temporal/samples/listworkflows/Starter.java b/core/src/main/java/io/temporal/samples/listworkflows/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/listworkflows/Starter.java rename to core/src/main/java/io/temporal/samples/listworkflows/Starter.java diff --git a/src/main/java/io/temporal/samples/metrics/MetricsStarter.java b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/metrics/MetricsStarter.java rename to core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java diff --git a/src/main/java/io/temporal/samples/metrics/MetricsUtils.java b/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java similarity index 100% rename from src/main/java/io/temporal/samples/metrics/MetricsUtils.java rename to core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java diff --git a/src/main/java/io/temporal/samples/metrics/MetricsWorker.java b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/metrics/MetricsWorker.java rename to core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java diff --git a/src/main/java/io/temporal/samples/metrics/README.md b/core/src/main/java/io/temporal/samples/metrics/README.md similarity index 100% rename from src/main/java/io/temporal/samples/metrics/README.md rename to core/src/main/java/io/temporal/samples/metrics/README.md diff --git a/src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java b/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java rename to core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java diff --git a/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java b/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java rename to core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java diff --git a/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java b/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java rename to core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java diff --git a/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java b/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/moneybatch/Account.java b/core/src/main/java/io/temporal/samples/moneybatch/Account.java similarity index 100% rename from src/main/java/io/temporal/samples/moneybatch/Account.java rename to core/src/main/java/io/temporal/samples/moneybatch/Account.java diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java rename to core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/moneybatch/AccountImpl.java rename to core/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java rename to core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java rename to core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/moneybatch/README.md b/core/src/main/java/io/temporal/samples/moneybatch/README.md similarity index 100% rename from src/main/java/io/temporal/samples/moneybatch/README.md rename to core/src/main/java/io/temporal/samples/moneybatch/README.md diff --git a/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java b/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java similarity index 100% rename from src/main/java/io/temporal/samples/moneybatch/TransferRequester.java rename to core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java diff --git a/src/main/java/io/temporal/samples/moneytransfer/Account.java b/core/src/main/java/io/temporal/samples/moneytransfer/Account.java similarity index 100% rename from src/main/java/io/temporal/samples/moneytransfer/Account.java rename to core/src/main/java/io/temporal/samples/moneytransfer/Account.java diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java rename to core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java rename to core/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java rename to core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java rename to core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/moneytransfer/README.MD b/core/src/main/java/io/temporal/samples/moneytransfer/README.MD similarity index 100% rename from src/main/java/io/temporal/samples/moneytransfer/README.MD rename to core/src/main/java/io/temporal/samples/moneytransfer/README.MD diff --git a/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java b/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java similarity index 100% rename from src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java rename to core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java diff --git a/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java rename to core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java diff --git a/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java rename to core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java diff --git a/src/main/java/io/temporal/samples/payloadconverter/cloudevents/README.md b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/README.md similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/cloudevents/README.md rename to core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/README.md diff --git a/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java rename to core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java diff --git a/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java rename to core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java diff --git a/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java rename to core/src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java diff --git a/src/main/java/io/temporal/samples/payloadconverter/crypto/README.md b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/README.md similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/crypto/README.md rename to core/src/main/java/io/temporal/samples/payloadconverter/crypto/README.md diff --git a/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java rename to core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java diff --git a/src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java b/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java rename to core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java diff --git a/src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java rename to core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java diff --git a/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java b/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java rename to core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java diff --git a/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java b/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/peractivityoptions/README.md b/core/src/main/java/io/temporal/samples/peractivityoptions/README.md similarity index 100% rename from src/main/java/io/temporal/samples/peractivityoptions/README.md rename to core/src/main/java/io/temporal/samples/peractivityoptions/README.md diff --git a/src/main/java/io/temporal/samples/peractivityoptions/Starter.java b/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/peractivityoptions/Starter.java rename to core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java diff --git a/src/main/java/io/temporal/samples/polling/PollingActivities.java b/core/src/main/java/io/temporal/samples/polling/PollingActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/PollingActivities.java rename to core/src/main/java/io/temporal/samples/polling/PollingActivities.java diff --git a/src/main/java/io/temporal/samples/polling/PollingWorkflow.java b/core/src/main/java/io/temporal/samples/polling/PollingWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/PollingWorkflow.java rename to core/src/main/java/io/temporal/samples/polling/PollingWorkflow.java diff --git a/src/main/java/io/temporal/samples/polling/README.md b/core/src/main/java/io/temporal/samples/polling/README.md similarity index 100% rename from src/main/java/io/temporal/samples/polling/README.md rename to core/src/main/java/io/temporal/samples/polling/README.md diff --git a/src/main/java/io/temporal/samples/polling/TestService.java b/core/src/main/java/io/temporal/samples/polling/TestService.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/TestService.java rename to core/src/main/java/io/temporal/samples/polling/TestService.java diff --git a/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java rename to core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java diff --git a/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java rename to core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java diff --git a/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/polling/frequent/README.md b/core/src/main/java/io/temporal/samples/polling/frequent/README.md similarity index 100% rename from src/main/java/io/temporal/samples/polling/frequent/README.md rename to core/src/main/java/io/temporal/samples/polling/frequent/README.md diff --git a/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java rename to core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java diff --git a/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java rename to core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java diff --git a/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/polling/infrequent/README.md b/core/src/main/java/io/temporal/samples/polling/infrequent/README.md similarity index 100% rename from src/main/java/io/temporal/samples/polling/infrequent/README.md rename to core/src/main/java/io/temporal/samples/polling/infrequent/README.md diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java rename to core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java rename to core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java rename to core/src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java diff --git a/src/main/java/io/temporal/samples/polling/periodicsequence/README.md b/core/src/main/java/io/temporal/samples/polling/periodicsequence/README.md similarity index 100% rename from src/main/java/io/temporal/samples/polling/periodicsequence/README.md rename to core/src/main/java/io/temporal/samples/polling/periodicsequence/README.md diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java diff --git a/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java similarity index 100% rename from src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java rename to core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java diff --git a/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java b/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java rename to core/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java diff --git a/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java b/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java rename to core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java diff --git a/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/terminateworkflow/README.md b/core/src/main/java/io/temporal/samples/terminateworkflow/README.md similarity index 100% rename from src/main/java/io/temporal/samples/terminateworkflow/README.md rename to core/src/main/java/io/temporal/samples/terminateworkflow/README.md diff --git a/src/main/java/io/temporal/samples/terminateworkflow/Starter.java b/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/terminateworkflow/Starter.java rename to core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java diff --git a/src/main/java/io/temporal/samples/tracing/JaegerUtils.java b/core/src/main/java/io/temporal/samples/tracing/JaegerUtils.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/JaegerUtils.java rename to core/src/main/java/io/temporal/samples/tracing/JaegerUtils.java diff --git a/src/main/java/io/temporal/samples/tracing/README.md b/core/src/main/java/io/temporal/samples/tracing/README.md similarity index 100% rename from src/main/java/io/temporal/samples/tracing/README.md rename to core/src/main/java/io/temporal/samples/tracing/README.md diff --git a/src/main/java/io/temporal/samples/tracing/Starter.java b/core/src/main/java/io/temporal/samples/tracing/Starter.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/Starter.java rename to core/src/main/java/io/temporal/samples/tracing/Starter.java diff --git a/src/main/java/io/temporal/samples/tracing/TracingWorker.java b/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/TracingWorker.java rename to core/src/main/java/io/temporal/samples/tracing/TracingWorker.java diff --git a/src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java rename to core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java diff --git a/src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java rename to core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java diff --git a/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java rename to core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java diff --git a/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java rename to core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java diff --git a/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java similarity index 100% rename from src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java rename to core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java diff --git a/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java similarity index 100% rename from src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java rename to core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java diff --git a/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java similarity index 100% rename from src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java rename to core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java diff --git a/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java similarity index 100% rename from src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java rename to core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java diff --git a/src/main/java/io/temporal/samples/updatabletimer/README.md b/core/src/main/java/io/temporal/samples/updatabletimer/README.md similarity index 100% rename from src/main/java/io/temporal/samples/updatabletimer/README.md rename to core/src/main/java/io/temporal/samples/updatabletimer/README.md diff --git a/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java b/core/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java similarity index 100% rename from src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java rename to core/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java diff --git a/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java b/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java similarity index 100% rename from src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java rename to core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java diff --git a/src/main/resources/dsl/bankingtransactions/datainput.json b/core/src/main/resources/dsl/bankingtransactions/datainput.json similarity index 100% rename from src/main/resources/dsl/bankingtransactions/datainput.json rename to core/src/main/resources/dsl/bankingtransactions/datainput.json diff --git a/src/main/resources/dsl/bankingtransactions/workflow.json b/core/src/main/resources/dsl/bankingtransactions/workflow.json similarity index 100% rename from src/main/resources/dsl/bankingtransactions/workflow.json rename to core/src/main/resources/dsl/bankingtransactions/workflow.json diff --git a/src/main/resources/dsl/bankingtransactions/workflow.yml b/core/src/main/resources/dsl/bankingtransactions/workflow.yml similarity index 100% rename from src/main/resources/dsl/bankingtransactions/workflow.yml rename to core/src/main/resources/dsl/bankingtransactions/workflow.yml diff --git a/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json b/core/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json similarity index 100% rename from src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json rename to core/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json diff --git a/src/main/resources/dsl/bankingtransactionssubflow/datainput.json b/core/src/main/resources/dsl/bankingtransactionssubflow/datainput.json similarity index 100% rename from src/main/resources/dsl/bankingtransactionssubflow/datainput.json rename to core/src/main/resources/dsl/bankingtransactionssubflow/datainput.json diff --git a/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json b/core/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json similarity index 100% rename from src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json rename to core/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json diff --git a/src/main/resources/dsl/customerapplication/datainput.json b/core/src/main/resources/dsl/customerapplication/datainput.json similarity index 100% rename from src/main/resources/dsl/customerapplication/datainput.json rename to core/src/main/resources/dsl/customerapplication/datainput.json diff --git a/src/main/resources/dsl/customerapplication/workflow.json b/core/src/main/resources/dsl/customerapplication/workflow.json similarity index 100% rename from src/main/resources/dsl/customerapplication/workflow.json rename to core/src/main/resources/dsl/customerapplication/workflow.json diff --git a/src/main/resources/dsl/customerapplication/workflow.yml b/core/src/main/resources/dsl/customerapplication/workflow.yml similarity index 100% rename from src/main/resources/dsl/customerapplication/workflow.yml rename to core/src/main/resources/dsl/customerapplication/workflow.yml diff --git a/src/main/resources/dsl/customerapproval/applicantdatainput.json b/core/src/main/resources/dsl/customerapproval/applicantdatainput.json similarity index 100% rename from src/main/resources/dsl/customerapproval/applicantdatainput.json rename to core/src/main/resources/dsl/customerapproval/applicantdatainput.json diff --git a/src/main/resources/dsl/customerapproval/applicantworkflow.json b/core/src/main/resources/dsl/customerapproval/applicantworkflow.json similarity index 100% rename from src/main/resources/dsl/customerapproval/applicantworkflow.json rename to core/src/main/resources/dsl/customerapproval/applicantworkflow.json diff --git a/src/main/resources/dsl/customerapproval/approvaldatainput.json b/core/src/main/resources/dsl/customerapproval/approvaldatainput.json similarity index 100% rename from src/main/resources/dsl/customerapproval/approvaldatainput.json rename to core/src/main/resources/dsl/customerapproval/approvaldatainput.json diff --git a/src/main/resources/dsl/customerapproval/approvalworkflow.json b/core/src/main/resources/dsl/customerapproval/approvalworkflow.json similarity index 100% rename from src/main/resources/dsl/customerapproval/approvalworkflow.json rename to core/src/main/resources/dsl/customerapproval/approvalworkflow.json diff --git a/src/main/resources/logback.xml b/core/src/main/resources/logback.xml similarity index 100% rename from src/main/resources/logback.xml rename to core/src/main/resources/logback.xml diff --git a/src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java b/core/src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java similarity index 100% rename from src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java rename to core/src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java diff --git a/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java b/core/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java similarity index 100% rename from src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java rename to core/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java diff --git a/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java b/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java similarity index 100% rename from src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java rename to core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java diff --git a/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java b/core/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java similarity index 100% rename from src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java rename to core/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java diff --git a/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowJUnit5Test.java b/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowJUnit5Test.java similarity index 100% rename from src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowJUnit5Test.java rename to core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowJUnit5Test.java diff --git a/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java b/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java similarity index 100% rename from src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java rename to core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java diff --git a/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java b/core/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java similarity index 100% rename from src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java rename to core/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java diff --git a/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java b/core/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java similarity index 100% rename from src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java rename to core/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java diff --git a/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java b/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java similarity index 100% rename from src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java rename to core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java diff --git a/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java b/core/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java similarity index 93% rename from src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java rename to core/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java index 24985a7bf..cb0514134 100644 --- a/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java +++ b/core/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java @@ -68,12 +68,11 @@ public void testFailureMessageIsEncoded() { .setTaskQueue(testWorkflowRule.getTaskQueue()) .build()); - WorkflowFailedException exception = - assertThrows( - WorkflowFailedException.class, - () -> { - workflow.validateCustomer(new MyCustomer("John", 20)); - }); + assertThrows( + WorkflowFailedException.class, + () -> { + workflow.validateCustomer(new MyCustomer("John", 20)); + }); HistoryEvent wfExecFailedEvent = testWorkflowRule.getWorkflowClient().fetchHistory("CustomerAgeCheck").getLastEvent(); diff --git a/src/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java b/core/src/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java similarity index 100% rename from src/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java rename to core/src/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java diff --git a/src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java b/core/src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java similarity index 100% rename from src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java rename to core/src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java rename to core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java diff --git a/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java rename to core/src/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java diff --git a/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloActivityTest.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloActivityTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloActivityTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloAsyncTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAsyncTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloAsyncTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloAsyncTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java b/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java rename to core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java diff --git a/src/test/java/io/temporal/samples/hello/HelloChildTest.java b/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloChildTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloChildTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloCronTest.java b/core/src/test/java/io/temporal/samples/hello/HelloCronTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloCronTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloCronTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java b/core/src/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java rename to core/src/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java diff --git a/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java b/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloDynamicTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java b/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloExceptionTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java b/core/src/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java b/core/src/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloPeriodicTest.java b/core/src/test/java/io/temporal/samples/hello/HelloPeriodicTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloPeriodicTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloPeriodicTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java b/core/src/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloQueryTest.java b/core/src/test/java/io/temporal/samples/hello/HelloQueryTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloQueryTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloQueryTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java diff --git a/src/test/java/io/temporal/samples/hello/HelloSignalTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSignalTest.java similarity index 100% rename from src/test/java/io/temporal/samples/hello/HelloSignalTest.java rename to core/src/test/java/io/temporal/samples/hello/HelloSignalTest.java diff --git a/src/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java b/core/src/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java similarity index 100% rename from src/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java rename to core/src/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java diff --git a/src/test/java/io/temporal/samples/metrics/MetricsTest.java b/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java similarity index 100% rename from src/test/java/io/temporal/samples/metrics/MetricsTest.java rename to core/src/test/java/io/temporal/samples/metrics/MetricsTest.java diff --git a/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java b/core/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java similarity index 100% rename from src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java rename to core/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java diff --git a/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java b/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java similarity index 100% rename from src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java rename to core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java diff --git a/src/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java b/core/src/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java similarity index 100% rename from src/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java rename to core/src/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java diff --git a/src/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java b/core/src/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java similarity index 100% rename from src/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java rename to core/src/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java diff --git a/src/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java b/core/src/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java similarity index 100% rename from src/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java rename to core/src/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java diff --git a/src/test/java/io/temporal/samples/polling/FrequentPollingTest.java b/core/src/test/java/io/temporal/samples/polling/FrequentPollingTest.java similarity index 100% rename from src/test/java/io/temporal/samples/polling/FrequentPollingTest.java rename to core/src/test/java/io/temporal/samples/polling/FrequentPollingTest.java diff --git a/src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java b/core/src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java similarity index 100% rename from src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java rename to core/src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java diff --git a/src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java b/core/src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java similarity index 100% rename from src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java rename to core/src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java diff --git a/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java b/core/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java similarity index 100% rename from src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java rename to core/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java diff --git a/src/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java b/core/src/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java similarity index 100% rename from src/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java rename to core/src/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java diff --git a/src/test/java/io/temporal/samples/tracing/TracingTest.java b/core/src/test/java/io/temporal/samples/tracing/TracingTest.java similarity index 100% rename from src/test/java/io/temporal/samples/tracing/TracingTest.java rename to core/src/test/java/io/temporal/samples/tracing/TracingTest.java diff --git a/src/test/resources/dsl/bankingtransactions/datainput.json b/core/src/test/resources/dsl/bankingtransactions/datainput.json similarity index 100% rename from src/test/resources/dsl/bankingtransactions/datainput.json rename to core/src/test/resources/dsl/bankingtransactions/datainput.json diff --git a/src/test/resources/dsl/bankingtransactions/workflow.json b/core/src/test/resources/dsl/bankingtransactions/workflow.json similarity index 100% rename from src/test/resources/dsl/bankingtransactions/workflow.json rename to core/src/test/resources/dsl/bankingtransactions/workflow.json diff --git a/src/test/resources/dsl/bankingtransactions/workflow.yml b/core/src/test/resources/dsl/bankingtransactions/workflow.yml similarity index 100% rename from src/test/resources/dsl/bankingtransactions/workflow.yml rename to core/src/test/resources/dsl/bankingtransactions/workflow.yml diff --git a/src/test/resources/dsl/customerapplication/datainput.json b/core/src/test/resources/dsl/customerapplication/datainput.json similarity index 100% rename from src/test/resources/dsl/customerapplication/datainput.json rename to core/src/test/resources/dsl/customerapplication/datainput.json diff --git a/src/test/resources/dsl/customerapplication/workflow.json b/core/src/test/resources/dsl/customerapplication/workflow.json similarity index 100% rename from src/test/resources/dsl/customerapplication/workflow.json rename to core/src/test/resources/dsl/customerapplication/workflow.json diff --git a/src/test/resources/dsl/customerapplication/workflow.yml b/core/src/test/resources/dsl/customerapplication/workflow.yml similarity index 100% rename from src/test/resources/dsl/customerapplication/workflow.yml rename to core/src/test/resources/dsl/customerapplication/workflow.yml diff --git a/settings.gradle b/settings.gradle index 041e593de..4594514ab 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,4 @@ rootProject.name = 'temporal-java-samples' +include 'core' +include 'springboot' diff --git a/springboot/build.gradle b/springboot/build.gradle new file mode 100644 index 000000000..ab573d69a --- /dev/null +++ b/springboot/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'org.springframework.boot' + +dependencies { + implementation "org.springframework.boot:spring-boot-starter-web" + implementation "org.springframework.boot:spring-boot-starter-actuator" + implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" + testImplementation "org.springframework.boot:spring-boot-starter-test" + dependencies { + errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') + if (JavaVersion.current().isJava11Compatible()) { + errorprone('com.google.errorprone:error_prone_core:2.18.0') + } else { + errorprone('com.google.errorprone:error_prone_core:2.18.0') + } + } +} + +bootJar { + enabled = false +} + +jar { + enabled = true +} \ No newline at end of file diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java new file mode 100644 index 000000000..e2d483349 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.springboot.hello.HelloWorkflow; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SamplesController { + + @Autowired WorkflowClient client; + + @GetMapping("/hello/{name}") + String helloSample(@PathVariable String name) { + HelloWorkflow workflow = + client.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("HelloSampleTaskQueue") + .setWorkflowId("HelloSample") + .build()); + + return workflow.sayHello(name); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java b/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java new file mode 100644 index 000000000..88ca068a1 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TemporalSpringbootSamplesApplication { + public static void main(String[] args) { + SpringApplication.run(TemporalSpringbootSamplesApplication.class, args).start(); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java new file mode 100644 index 000000000..a2306b24c --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface HelloActivity { + String hello(String name); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java new file mode 100644 index 000000000..817bd40f7 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello; + +import io.temporal.spring.boot.ActivityImpl; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@ActivityImpl(taskQueues = "HelloSampleTaskQueue") +public class HelloActivityImpl implements HelloActivity { + @Value("${samples.data.language}") + private String language; + + @Override + public String hello(String name) { + String greeting = language.equals("spanish") ? "Hola " : "Hello "; + return greeting + name + "!"; + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java new file mode 100644 index 000000000..183f5ac44 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloWorkflow { + @WorkflowMethod + String sayHello(String message); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java new file mode 100644 index 000000000..59e28642d --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello; + +import io.temporal.activity.ActivityOptions; +import io.temporal.spring.boot.WorkflowImpl; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +@WorkflowImpl(taskQueues = "HelloSampleTaskQueue") +public class HelloWorkflowImpl implements HelloWorkflow { + + private HelloActivity activity = + Workflow.newActivityStub( + HelloActivity.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String sayHello(String name) { + return activity.hello(name); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md b/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md new file mode 100644 index 000000000..c5e952146 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md @@ -0,0 +1,15 @@ +# SpringBoot Hello Sample + +1. Start SpringBoot from main samples repo directory: + + ./gradlew bootRun + +2. In your browser navigate to: + + http://localhost:3030/hello/Temporal%20User + +You should see "Hello Temporal User!" show on the page which is the result of our +Hello workflow execution. + +You can try changing the language setting in [application.yaml](../../../../../../resources/application.yaml) file +from "english" to "spanish" to get the greeting result in Spanish. \ No newline at end of file diff --git a/springboot/src/main/resources/application.yaml b/springboot/src/main/resources/application.yaml new file mode 100644 index 000000000..dc13d5ff7 --- /dev/null +++ b/springboot/src/main/resources/application.yaml @@ -0,0 +1,26 @@ +server: + port: 3030 +spring: + application: + name: temporal-samples + temporal: + connection: + target: 127.0.0.1:7233 + target.namespace: default +# (Note following configuration are not set by default but serve more as reference) +# workers: +# - task-queue: DemoTaskQueue +# capacity: +# max-concurrent-workflow-task-pollers: 6 +# max-concurrent-activity-task-pollers: 6 +# rate-limits: +# max-worker-activities-per-second: 3 +# max-task-queue-activities-per-second: 3 +# workflow-cache: +# max-instances: 10 +# max-threads: 10 + workersAutoDiscovery: + packages: io.temporal.samples.springboot +samples: + data: + language: english \ No newline at end of file diff --git a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java new file mode 100644 index 000000000..586df5a80 --- /dev/null +++ b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.springboot.hello.HelloWorkflow; +import io.temporal.testing.TestWorkflowEnvironment; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.util.Assert; + +@SpringBootTest(classes = HelloSampleTest.Configuration.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class HelloSampleTest { + + @Autowired ConfigurableApplicationContext applicationContext; + + @Autowired TestWorkflowEnvironment testWorkflowEnvironment; + + @Autowired WorkflowClient workflowClient; + + @BeforeEach + void setUp() { + applicationContext.start(); + } + + @Test + public void testHello() { + HelloWorkflow workflow = + workflowClient.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("HelloSampleTaskQueue") + .setWorkflowId("HelloSampleTest") + .build()); + String result = workflow.sayHello("Temporal User"); + Assert.notNull(result, "Greeting should not be null"); + Assert.isTrue(result.equals("Hello Temporal User!"), "Invalid result"); + } + + @ComponentScan + public static class Configuration {} +} diff --git a/springboot/src/test/resources/application.yaml b/springboot/src/test/resources/application.yaml new file mode 100644 index 000000000..95ab48335 --- /dev/null +++ b/springboot/src/test/resources/application.yaml @@ -0,0 +1,16 @@ +server: + port: 3030 +spring: + application: + name: temporal-samples + temporal: + connection: + target: 127.0.0.1:7233 + target.namespace: default + workersAutoDiscovery: + packages: io.temporal.samples.springboot + test-server: + enabled: true +samples: + data: + language: english \ No newline at end of file From d4c1ef23c2fd2b3b0594c5b6e10feeb65ba543db Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 12 Jun 2023 09:54:05 -0700 Subject: [PATCH 079/240] Add sample showing sync update (#469) Add sample showing sync update --- build.gradle | 2 +- .../temporal/samples/hello/HelloUpdate.java | 296 ++++++++++++++++++ .../java/io/temporal/samples/hello/README.md | 1 + .../samples/hello/HelloUpdateTest.java | 88 ++++++ 4 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloUpdate.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloUpdateTest.java diff --git a/build.gradle b/build.gradle index 8dfd51515..b06f42ff5 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ subprojects { ext { otelVersion = '1.26.0' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.19.1' + javaSDKVersion = '1.20.0-SNAPSHOT' jarVersion = '1.0.0' } diff --git a/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java b/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java new file mode 100644 index 000000000..79f20336b --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import com.google.common.base.Throwables; +import io.temporal.activity.ActivityOptions; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.client.WorkflowUpdateException; +import io.temporal.failure.ApplicationFailure; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.UpdateMethod; +import io.temporal.workflow.UpdateValidatorMethod; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +/** + * Sample Temporal workflow that demonstrates how to use workflow update methods to update a + * workflow execution from external sources. Workflow update is another way to interact with a + * running workflow along with signals and queries. Workflow update combines aspects of signals and + * queries. Like signals, workflow update can mutate workflow state. Like queries, workflow update + * can return a value. + * + *

Note: Make sure to set {@code frontend.enableUpdateWorkflowExecution=true} in your Temporal + * config to enabled update. + */ +public class HelloUpdate { + + // Define the task queue name + static final String TASK_QUEUE = "HelloUpdateTaskQueue"; + + // Define the workflow unique id + static final String WORKFLOW_ID = "HelloUpdateWorkflow"; + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see WorkflowInterface + * @see WorkflowMethod + */ + @WorkflowInterface + public interface GreetingWorkflow { + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + List getGreetings(); + + /* + * Define the workflow addGreeting update method. This method is executed when the workflow + * receives an update request. + */ + @UpdateMethod + int addGreeting(String name); + + /* + * Define an optional workflow update validator. The validator must take the same parameters as the update handle. + * The validator is run before the update handle. + * If the validator fails by throwing any exception the update request will be rejected and the handle will not run. + * If the validator passes the update will be considered accepted and the handler will run. + */ + @UpdateValidatorMethod(updateName = "addGreeting") + void addGreetingValidator(String name); + + // Define the workflow exit signal method. This method is executed when the workflow receives a + // signal. + @SignalMethod + void exit(); + } + + // Define the workflow implementation which implements the getGreetings workflow method. + public static class GreetingWorkflowImpl implements GreetingWorkflow { + + // messageQueue holds up to 10 messages (received from updates) + private final List messageQueue = new ArrayList<>(10); + private final List receivedMessages = new ArrayList<>(10); + private boolean exit = false; + + private final HelloActivity.GreetingActivities activities = + Workflow.newActivityStub( + HelloActivity.GreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public List getGreetings() { + + while (true) { + // Block current thread until the unblocking condition is evaluated to true + Workflow.await(() -> !messageQueue.isEmpty() || exit); + if (messageQueue.isEmpty() && exit) { + /* + * no messages in queue and exit signal was sent, return the received messages. + * + * Note: A accepted update will not stop workflow completion. If a workflow tries to complete after an update + * has been sent by a client, but before it has been accepted by the workflow, the workflow will not complete. + */ + return receivedMessages; + } + String message = messageQueue.remove(0); + receivedMessages.add(message); + } + } + + @Override + public int addGreeting(String name) { + if (name.isEmpty()) { + /* + * Updates can fail by throwing a TemporalFailure. All other exceptions cause the workflow + * task to fail and potentially retried. + * + * Note: A check like this could (and should) belong in the validator, this is just to demonstrate failing an + * update. + */ + throw ApplicationFailure.newFailure("Cannot greet someone with an empty name", "Failure"); + } + // Updates can mutate workflow state like variables or call activities + messageQueue.add(activities.composeGreeting("Hello", name)); + // Updates can return data back to the client + return receivedMessages.size() + messageQueue.size(); + } + + @Override + public void addGreetingValidator(String name) { + /* + * Update validators have the same restrictions as Queries. So workflow state cannot be + * mutated inside a validator. + */ + if (receivedMessages.size() >= 10) { + /* + * Throwing any exception inside an update validator will cause the update to be rejected. + * Note: rejected update will not appear in the workflow history + */ + throw new IllegalStateException("Only 10 greetings may be added"); + } + } + + @Override + public void exit() { + exit = true; + } + } + + /** + * With the Workflow and Activities defined, we can now start execution. The main method starts + * the worker and then the workflow. + */ + public static void main(String[] args) throws Exception { + + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register the workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); + + /* + * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, + * the Activity Type is a shared instance. + */ + worker.registerActivitiesImplementations(new HelloActivity.GreetingActivitiesImpl()); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + // Create the workflow options + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(WORKFLOW_ID).build(); + + // Create the workflow client stub. It is used to start the workflow execution. + GreetingWorkflow workflow = client.newWorkflowStub(GreetingWorkflow.class, workflowOptions); + + // Start workflow asynchronously and call its getGreeting workflow method + WorkflowClient.start(workflow::getGreetings); + + // After start for getGreeting returns, the workflow is guaranteed to be started. + // So we can send an update to it using the workflow stub. + // This workflow keeps receiving updates until exit is called + + // When the workflow is started the getGreetings will block for the previously defined + // conditions + // Send the first workflow update + workflow.addGreeting("World"); + + /* + * Here we create a new workflow stub using the same workflow id. + * We do this to demonstrate that to send an update to an already running workflow + * you only need to know its workflow id. + */ + GreetingWorkflow workflowById = client.newWorkflowStub(GreetingWorkflow.class, WORKFLOW_ID); + + // Send the second update to our workflow + workflowById.addGreeting("Universe"); + + /* + * Create an untyped workflow stub to demonstrate sending an update + * with the untyped stub. + */ + WorkflowStub greetingStub = client.newUntypedWorkflowStub(WORKFLOW_ID); + greetingStub.update("addGreeting", int.class, "Temporal"); + + try { + // The update request will fail on a empty name and the exception will be thrown here. + workflowById.addGreeting(""); + System.exit(-1); + } catch (WorkflowUpdateException e) { + Throwable cause = Throwables.getRootCause(e); + /* + * Here we should get our originally thrown ApplicationError + * and the message "Cannot greet someone with an empty name". + */ + System.out.println("\n Update failed, root cause: " + cause.getMessage()); + } + // Send our update validators limit of 10 updates + int sentUpdates = workflowById.addGreeting("Update"); + while (sentUpdates < 10) { + sentUpdates = workflowById.addGreeting("Again"); + } + + // The update request will be rejected because our validator will fail + try { + workflowById.addGreeting("Will be rejected"); + System.exit(-1); + } catch (WorkflowUpdateException e) { + Throwable cause = Throwables.getRootCause(e); + System.out.println("\n Update rejected: " + cause.getMessage()); + } + + // Now let's send our exit signal to the workflow + workflowById.exit(); + + /* + * We now call our getGreetings workflow method synchronously after our workflow has started. + * This reconnects our workflowById workflow stub to the existing workflow and blocks until + * a result is available. Note that this behavior assumes that WorkflowOptions are not configured + * with WorkflowIdReusePolicy.AllowDuplicate. If they were, this call would fail with the + * WorkflowExecutionAlreadyStartedException exception. + */ + List greetings = workflowById.getGreetings(); + + // Print our two greetings which were sent by signals + System.out.println(greetings); + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md index 357cb5eb4..b191dcae3 100644 --- a/core/src/main/java/io/temporal/samples/hello/README.md +++ b/core/src/main/java/io/temporal/samples/hello/README.md @@ -28,4 +28,5 @@ To run each hello world sample, use one of the following commands: ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignal ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSearchAttributes ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSideEffect +./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloUpdate ``` diff --git a/core/src/test/java/io/temporal/samples/hello/HelloUpdateTest.java b/core/src/test/java/io/temporal/samples/hello/HelloUpdateTest.java new file mode 100644 index 000000000..fb41b2dd5 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloUpdateTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; + +import io.temporal.api.enums.v1.WorkflowIdReusePolicy; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.hello.HelloUpdate.GreetingWorkflow; +import io.temporal.testing.TestWorkflowRule; +import java.time.Duration; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; + +/** Unit test for {@link HelloUpdateTest}. Doesn't use an external Temporal service. */ +public class HelloUpdateTest { + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(HelloUpdate.GreetingWorkflowImpl.class) + .setDoNotStart(true) + .build(); + + @Test + public void testUpdate() { + // Setup mocks + HelloActivity.GreetingActivities activities = + mock(HelloActivity.GreetingActivities.class, withSettings().withoutAnnotations()); + when(activities.composeGreeting("Hello", "World")).thenReturn("Hello World!"); + when(activities.composeGreeting("Hello", "Universe")).thenReturn("Hello Universe!"); + testWorkflowRule.getWorker().registerActivitiesImplementations(activities); + testWorkflowRule.getTestEnvironment().start(); + // Get a workflow stub using the same task queue the worker uses. + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowIdReusePolicy( + WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE) + .build(); + GreetingWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(GreetingWorkflow.class, workflowOptions); + + // Start workflow asynchronously to not use another thread to update. + WorkflowClient.start(workflow::getGreetings); + + // After start for getGreeting returns, the workflow is guaranteed to be started. + // So we can send a update to it using workflow stub immediately. + // But just to demonstrate the unit testing of a long running workflow adding a long sleep here. + testWorkflowRule.getTestEnvironment().sleep(Duration.ofDays(1)); + // This workflow keeps receiving updates until exit is called + assertEquals(1, workflow.addGreeting("World")); + assertEquals(2, workflow.addGreeting("Universe")); + workflow.exit(); + // Calling synchronous getGreeting after workflow has started reconnects to the existing + // workflow and + // blocks until result is available. Note that this behavior assumes that WorkflowOptions are + // not configured + // with WorkflowIdReusePolicy.AllowDuplicate. In that case the call would fail with + // WorkflowExecutionAlreadyStartedException. + List greetings = workflow.getGreetings(); + assertEquals(2, greetings.size()); + assertEquals("Hello World!", greetings.get(0)); + assertEquals("Hello Universe!", greetings.get(1)); + } +} From 43b761ff17c884f54bcb1414e7abaf4427d5ded0 Mon Sep 17 00:00:00 2001 From: Elan Hasson <234704+ElanHasson@users.noreply.github.com> Date: Mon, 12 Jun 2023 23:32:44 -0400 Subject: [PATCH 080/240] Fix links in DSL sample (#470) * Fix links in sample * Round 2 --- core/src/main/java/io/temporal/samples/dsl/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/dsl/README.md b/core/src/main/java/io/temporal/samples/dsl/README.md index 476d3a5d4..d89dfade6 100644 --- a/core/src/main/java/io/temporal/samples/dsl/README.md +++ b/core/src/main/java/io/temporal/samples/dsl/README.md @@ -9,12 +9,12 @@ Since this is just a sample, this sample provides only partial implementation of entire [Serverless Workflow](https://serverlessworkflow.io/) DSL features. This sample runs the following DSL workflows: -1. [`customerapplication/workflow.yml`](/src/main/resources/dsl/customerapplication/workflow.yml) -2. [`bankingtransactions/workflow.yml`](/src/main/resources/dsl/bankingtransactions/workflow.yml) -3. [`customerapproval/applicantworkflow.json`](/src/main/resources/dsl/customerapproval/applicantworkflow.json) -4. [`customerapproval/approvalworkflow.json`](/src/main/resources/dsl/customerapproval/approvalworkflow.json) -5. [`bankingtransactionssubflow/parentworkflow.json`](/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json) -6. [`bankingtransactionssubflow/childworkflow.json`](/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json) +1. [`customerapplication/workflow.yml`](../../../../../resources/dsl/customerapplication/workflow.yml) +2. [`bankingtransactions/workflow.yml`](../../../../../resources/dsl/bankingtransactions/workflow.yml) +3. [`customerapproval/applicantworkflow.json`](../../../../../resources/dsl/customerapproval/applicantworkflow.json) +4. [`customerapproval/approvalworkflow.json`](../../../../../resources/dsl/customerapproval/approvalworkflow.json) +5. [`bankingtransactionssubflow/parentworkflow.json`](../../../../../resources/dsl/bankingtransactionssubflow/parentworkflow.json) +6. [`bankingtransactionssubflow/childworkflow.json`](../../../../../resources/dsl/bankingtransactionssubflow/childworkflow.json) Note that most DSLs, including Serverless Workflow DSL used in this sample represent their Workflow data as JSON. As such manipulation of this data is done via expression languages From 9d144cc1156817a635fb2d890febf30c0f8f67e0 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Fri, 16 Jun 2023 13:49:48 -0700 Subject: [PATCH 081/240] Add sample showing schedules API (#471) Add sample showing schedules API --- README.md | 3 + .../samples/hello/HelloSchedules.java | 266 ++++++++++++++++++ .../java/io/temporal/samples/hello/README.md | 1 + 3 files changed, 270 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloSchedules.java diff --git a/README.md b/README.md index 00ed6f992..1a37d420a 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,13 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloLocalActivity**](/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java): Demonstrates the use of a [Local Activity](https://docs.temporal.io/docs/jargon/mesh/#local-activity). - [**HelloPolymorphicActivity**](/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java): Demonstrates Activity Definitions that extend a common interface. - [**HelloQuery**](/core/src/main/java/io/temporal/samples/hello/HelloQuery.java): Demonstrates how to Query the state of a Workflow Execution. + - [**HelloSchedules**](/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java): Demonstrates how to create and interact with a Schedule. - [**HelloSignal**](/core/src/main/java/io/temporal/samples/hello/HelloSignal.java): Demonstrates how to send and handle a Signal. - [**HelloSaga**](/core/src/main/java/io/temporal/samples/hello/HelloSaga.java): Demonstrates how to use the SAGA feature. - [**HelloSearchAttributes**](/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java): Demonstrates how to add custom Search Attributes to Workflow Executions. - [**HelloSideEffect**](/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. + - [**HelloUpdate**](/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java): Demonstrates how to create and interact with an Update. + #### Scenario-based samples diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java b/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java new file mode 100644 index 000000000..22a86f61f --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.activity.Activity; +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityOptions; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.enums.v1.ScheduleOverlapPolicy; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.schedules.*; +import io.temporal.common.converter.GlobalDataConverter; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.time.Duration; +import java.time.Instant; +import java.util.Collections; + +/** + * Sample Temporal workflow that demonstrates periodic workflow execution using a schedule. Schedule + * is a new feature in Temporal designed to replace Cron workflows. Schedules allow for greater + * control over when workflows are run and how they are run. + */ +public class HelloSchedules { + + // Define the task queue name + static final String TASK_QUEUE = "HelloScheduleTaskQueue"; + + // Define the workflow unique id + static final String WORKFLOW_ID = "HelloScheduleWorkflow"; + + // Define the schedule unique id + static final String SCHEDULE_ID = "HelloSchedule"; + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see WorkflowInterface + * @see WorkflowMethod + */ + @WorkflowInterface + public interface GreetingWorkflow { + + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + void greet(String name); + } + + /** + * This is the Activity Definition's Interface. Activities are building blocks of any Temporal + * Workflow and contain any business logic that could perform long running computation, network + * calls, etc. + * + *

Annotating Activity Definition methods with @ActivityMethod is optional. + * + * @see ActivityInterface + * @see io.temporal.activity.ActivityMethod + */ + @ActivityInterface + public interface GreetingActivities { + + // Define your activity method which can be called during workflow execution + void greet(String greeting); + } + + // Define the workflow implementation which implements the greet workflow method. + public static class GreetingWorkflowImpl implements GreetingWorkflow { + + /** + * Define the GreetingActivities stub. Activity stubs are proxies for activity invocations that + * are executed outside of the workflow thread on the activity worker, that can be on a + * different host. Temporal is going to dispatch the activity results back to the workflow and + * unblock the stub as soon as activity is completed on the activity worker. + * + *

In the {@link ActivityOptions} definition the "setStartToCloseTimeout" option sets the + * maximum time of a single Activity execution attempt. For this example it is set to 10 + * seconds. + */ + private final GreetingActivities activities = + Workflow.newActivityStub( + GreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build()); + + @Override + public void greet(String name) { + // Workflow Executions started by a Schedule have the following + // additional properties appended to their search attributes. + Payload scheduledByIDPayload = + Workflow.getInfo().getSearchAttributes().getIndexedFieldsOrThrow("TemporalScheduledById"); + String scheduledByID = + GlobalDataConverter.get().fromPayload(scheduledByIDPayload, String.class, String.class); + + Payload startTimePayload = + Workflow.getInfo() + .getSearchAttributes() + .getIndexedFieldsOrThrow("TemporalScheduledStartTime"); + Instant startTime = + GlobalDataConverter.get().fromPayload(startTimePayload, Instant.class, Instant.class); + + activities.greet( + "Hello " + name + " from " + scheduledByID + " scheduled at " + startTime + "!"); + } + } + + /** + * Implementation of the workflow activity interface. It overwrites the defined greet activity + * method. + */ + static class GreetingActivitiesImpl implements GreetingActivities { + @Override + public void greet(String greeting) { + System.out.println( + "From " + Activity.getExecutionContext().getInfo().getWorkflowId() + ": " + greeting); + } + } + + /** + * With the Workflow and Activities defined, we can now start execution. The main method starts + * the worker and then the workflow. + */ + public static void main(String[] args) throws InterruptedException { + + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register the workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); + + /* + * Register the workflow activity implementation with the worker. Since workflow activities are + * stateless and thread-safe, we need to register a shared instance. + */ + worker.registerActivitiesImplementations(new GreetingActivitiesImpl()); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + /* + * Get a Schedule client which can be used to interact with schedule. + */ + ScheduleClient scheduleClient = ScheduleClient.newInstance(service); + + /* + * Create the workflow options for our schedule. + * Note: Not all workflow options are supported for schedules. + */ + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setWorkflowId(WORKFLOW_ID).setTaskQueue(TASK_QUEUE).build(); + + /* + * Create the action that will be run when the schedule is triggered. + */ + ScheduleActionStartWorkflow action = + ScheduleActionStartWorkflow.newBuilder() + .setWorkflowType(HelloSchedules.GreetingWorkflow.class) + .setArguments("World") + .setOptions(workflowOptions) + .build(); + + // Define the schedule we want to create + Schedule schedule = + Schedule.newBuilder().setAction(action).setSpec(ScheduleSpec.newBuilder().build()).build(); + + // Create a schedule on the server + ScheduleHandle handle = + scheduleClient.createSchedule(SCHEDULE_ID, schedule, ScheduleOptions.newBuilder().build()); + + // Manually trigger the schedule once + handle.trigger(ScheduleOverlapPolicy.SCHEDULE_OVERLAP_POLICY_ALLOW_ALL); + + // Update the schedule with a spec, so it will run periodically + handle.update( + (ScheduleUpdateInput input) -> { + Schedule.Builder builder = Schedule.newBuilder(input.getDescription().getSchedule()); + + builder.setSpec( + ScheduleSpec.newBuilder() + // Run the schedule at 5pm on Friday + .setCalendars( + Collections.singletonList( + ScheduleCalendarSpec.newBuilder() + .setHour(Collections.singletonList(new ScheduleRange(17))) + .setDayOfWeek(Collections.singletonList(new ScheduleRange(5))) + .build())) + // Run the schedule every 5s + .setIntervals( + Collections.singletonList(new ScheduleIntervalSpec(Duration.ofSeconds(5)))) + .build()); + // Make the schedule paused to demonstrate how to unpause a schedule + builder.setState( + ScheduleState.newBuilder() + .setPaused(true) + .setLimitedAction(true) + .setRemainingActions(10) + .build()); + return new ScheduleUpdate(builder.build()); + }); + + // Unpause schedule + handle.unpause(); + + // Wait for the schedule to run 10 actions + while (true) { + ScheduleState state = handle.describe().getSchedule().getState(); + if (state.getRemainingActions() == 0) { + break; + } + Thread.sleep(5000); + } + // Delete the schedule once the sample is done + handle.delete(); + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md index b191dcae3..925862c19 100644 --- a/core/src/main/java/io/temporal/samples/hello/README.md +++ b/core/src/main/java/io/temporal/samples/hello/README.md @@ -25,6 +25,7 @@ To run each hello world sample, use one of the following commands: ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPolymorphicActivity ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloQuery ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSaga +./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSchedules ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignal ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSearchAttributes ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSideEffect From 5ae487f0a427db3c5b44f0551a35a882bfa3d34f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Sat, 17 Jun 2023 17:52:27 +0200 Subject: [PATCH 082/240] added ssl full example and readme (#472) --- .../io/temporal/samples/ssl/MyWorkflow.java | 29 +++++++++++ .../temporal/samples/ssl/MyWorkflowImpl.java | 27 ++++++++++ .../java/io/temporal/samples/ssl/README.md | 22 ++++++++ .../{SslEnabledWorker.java => Starter.java} | 52 +++++++++++++++++-- .../samples/terminateworkflow/README.md | 2 +- 5 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/ssl/README.md rename core/src/main/java/io/temporal/samples/ssl/{SslEnabledWorker.java => Starter.java} (65%) diff --git a/core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java b/core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java new file mode 100644 index 000000000..a816ed45a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.ssl; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface MyWorkflow { + @WorkflowMethod + String execute(); +} diff --git a/core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java new file mode 100644 index 000000000..645e6a946 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.ssl; + +public class MyWorkflowImpl implements MyWorkflow { + @Override + public String execute() { + return "done"; + } +} diff --git a/core/src/main/java/io/temporal/samples/ssl/README.md b/core/src/main/java/io/temporal/samples/ssl/README.md new file mode 100644 index 000000000..187b5cc46 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/ssl/README.md @@ -0,0 +1,22 @@ +# Workflow execution with mTLS + + +This example shows how to secure your Temporal application with [mTLS](https://docs.temporal.io/security/#encryption-in-transit-with-mtls). +This is required to connect with Temporal Cloud or any production Temporal deployment. + + +## Export env variables +Before running the example you need to export the following env variables: + +- TEMPORAL_ENDPOINT: grpc endpoint, for Temporal Cloud would like `${namespace}.tmprl.cloud:7233`. +- TEMPORAL_NAMESPACE: Namespace. +- TEMPORAL_CLIENT_CERT: For Temporal Cloud see requirements [here](https://docs.temporal.io/cloud/how-to-manage-certificates-in-temporal-cloud#end-entity-certificates). +- TEMPORAL_CLIENT_KEY: For Temporal Cloud see requirements [here](https://docs.temporal.io/cloud/how-to-manage-certificates-in-temporal-cloud#end-entity-certificates). + + + +## Running this sample + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.ssl.Starter +``` diff --git a/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java b/core/src/main/java/io/temporal/samples/ssl/Starter.java similarity index 65% rename from core/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java rename to core/src/main/java/io/temporal/samples/ssl/Starter.java index 94ac07bf1..9b8c6170d 100644 --- a/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorker.java +++ b/core/src/main/java/io/temporal/samples/ssl/Starter.java @@ -21,16 +21,19 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowOptions; import io.temporal.serviceclient.SimpleSslContextBuilder; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import java.io.FileInputStream; import java.io.InputStream; -public class SslEnabledWorker { +public class Starter { static final String TASK_QUEUE = "MyTaskQueue"; + static final String WORKFLOW_ID = "HelloSSLWorkflow"; public static void main(String[] args) throws Exception { // Load your client certificate, which should look like: @@ -47,6 +50,7 @@ public static void main(String[] args) throws Exception { String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT"); // Your registered namespace. String namespace = System.getenv("TEMPORAL_NAMESPACE"); + // Create SSL enabled client by passing SslContext, created by SimpleSslContextBuilder. WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs( @@ -63,11 +67,49 @@ public static void main(String[] args) throws Exception { service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build()); // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); - // Worker that listens on a task queue and hosts both workflow and activity implementations. - factory.newWorker(TASK_QUEUE); - // TODO now register your workflow types and activity implementations. - // worker.registerWorkflowImplementationTypes(...); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register our workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); + + /** + * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, + * the Activity Type is a shared instance. + */ // worker.registerActivitiesImplementations(...); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ factory.start(); + + // Create the workflow client stub. It is used to start our workflow execution. + MyWorkflow workflow = + client.newWorkflowStub( + MyWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + /* + * Execute our workflow and wait for it to complete. The call to our execute method is + * synchronous. + */ + String greeting = workflow.execute(); + + // Display workflow execution results + System.out.println(greeting); + System.exit(0); } } diff --git a/core/src/main/java/io/temporal/samples/terminateworkflow/README.md b/core/src/main/java/io/temporal/samples/terminateworkflow/README.md index 54e78c9ff..82ab266a5 100644 --- a/core/src/main/java/io/temporal/samples/terminateworkflow/README.md +++ b/core/src/main/java/io/temporal/samples/terminateworkflow/README.md @@ -1,6 +1,6 @@ # Terminate Workflow execution -The sample demonstrates shows how to terminate Workflow Execution using the Client API. +The sample demonstrates how to terminate Workflow Execution using the Client API. ```bash ./gradlew -q execute -PmainClass=io.temporal.samples.terminateworkflow.Starter From 4deafc09c5ec1937ede05bee7be0823e92bebd25 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 20 Jun 2023 10:11:41 -0400 Subject: [PATCH 083/240] adding 'ui' to springboot samples (#476) * adding 'ui' to springboot samples Signed-off-by: Tihomir Surdilovic * fix text Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 10 ++- build.gradle | 1 + springboot/build.gradle | 1 + .../samples/springboot/SamplesController.java | 28 ++++++-- .../springboot/hello/HelloActivity.java | 3 +- .../springboot/hello/HelloActivityImpl.java | 5 +- .../springboot/hello/HelloWorkflow.java | 3 +- .../springboot/hello/HelloWorkflowImpl.java | 5 +- .../samples/springboot/hello/README.md | 7 +- .../springboot/hello/model/Person.java | 49 ++++++++++++++ .../src/main/resources/templates/hello.html | 65 +++++++++++++++++++ .../src/main/resources/templates/index.html | 28 ++++++++ .../samples/springboot/HelloSampleTest.java | 3 +- 13 files changed, 190 insertions(+), 18 deletions(-) create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java create mode 100644 springboot/src/main/resources/templates/hello.html create mode 100644 springboot/src/main/resources/templates/index.html diff --git a/README.md b/README.md index 1a37d420a..f901c8adc 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,15 @@ See the README.md file in each main sample directory for cut/paste Gradle comman ### Running SpringBoot Samples -See the README.md file in each main sample directory for cut/paste Gradle command to run specific example. +1. Start SpringBoot from main repo dir: + + ./gradlew bootRun + +2. Navigate to [localhost:3030](http://localhost:3030) + +3. Select which sample you want to run + +More info on each sample: - [**Hello**](/springboot/src/main/java/io/temporal/samples/springboot/hello): Invoke simple "Hello" workflow from a GET endpoint diff --git a/build.gradle b/build.gradle index b06f42ff5..6ff4f5dc6 100644 --- a/build.gradle +++ b/build.gradle @@ -38,6 +38,7 @@ subprojects { exclude '**/*.json' exclude '**/*.yaml' exclude '**/*.yml' + exclude '**/*.html' } if (JavaVersion.current().isJava11Compatible()) { diff --git a/springboot/build.gradle b/springboot/build.gradle index ab573d69a..26fcdc7f6 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'org.springframework.boot' dependencies { implementation "org.springframework.boot:spring-boot-starter-web" + implementation "org.springframework.boot:spring-boot-starter-thymeleaf" implementation "org.springframework.boot:spring-boot-starter-actuator" implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" testImplementation "org.springframework.boot:spring-boot-starter-test" diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index e2d483349..cf18a31c0 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -22,18 +22,31 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.samples.springboot.hello.HelloWorkflow; +import io.temporal.samples.springboot.hello.model.Person; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; -@RestController +@Controller public class SamplesController { @Autowired WorkflowClient client; - @GetMapping("/hello/{name}") - String helloSample(@PathVariable String name) { + @GetMapping("/hello") + public String hello(Model model) { + model.addAttribute("sample", "Say Hello"); + return "hello"; + } + + @PostMapping( + value = "/hello", + consumes = {MediaType.APPLICATION_JSON_VALUE}, + produces = {MediaType.TEXT_HTML_VALUE}) + ResponseEntity helloSample(@RequestBody Person person) { HelloWorkflow workflow = client.newWorkflowStub( HelloWorkflow.class, @@ -42,6 +55,7 @@ String helloSample(@PathVariable String name) { .setWorkflowId("HelloSample") .build()); - return workflow.sayHello(name); + // bypass thymeleaf, don't return template name just result + return new ResponseEntity("\"" + workflow.sayHello(person) + "\"", HttpStatus.OK); } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java index a2306b24c..d727696f0 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java @@ -20,8 +20,9 @@ package io.temporal.samples.springboot.hello; import io.temporal.activity.ActivityInterface; +import io.temporal.samples.springboot.hello.model.Person; @ActivityInterface public interface HelloActivity { - String hello(String name); + String hello(Person person); } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java index 817bd40f7..6dd3a39fe 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java @@ -19,6 +19,7 @@ package io.temporal.samples.springboot.hello; +import io.temporal.samples.springboot.hello.model.Person; import io.temporal.spring.boot.ActivityImpl; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -30,8 +31,8 @@ public class HelloActivityImpl implements HelloActivity { private String language; @Override - public String hello(String name) { + public String hello(Person person) { String greeting = language.equals("spanish") ? "Hola " : "Hello "; - return greeting + name + "!"; + return greeting + person.getFirstName() + " " + person.getLastName() + "!"; } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java index 183f5ac44..fd1675623 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java @@ -19,11 +19,12 @@ package io.temporal.samples.springboot.hello; +import io.temporal.samples.springboot.hello.model.Person; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloWorkflow { @WorkflowMethod - String sayHello(String message); + String sayHello(Person person); } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java index 59e28642d..05336a9f3 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java @@ -20,6 +20,7 @@ package io.temporal.samples.springboot.hello; import io.temporal.activity.ActivityOptions; +import io.temporal.samples.springboot.hello.model.Person; import io.temporal.spring.boot.WorkflowImpl; import io.temporal.workflow.Workflow; import java.time.Duration; @@ -33,7 +34,7 @@ public class HelloWorkflowImpl implements HelloWorkflow { ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); @Override - public String sayHello(String name) { - return activity.hello(name); + public String sayHello(Person person) { + return activity.hello(person); } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md b/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md index c5e952146..6c34c9445 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md @@ -6,10 +6,11 @@ 2. In your browser navigate to: - http://localhost:3030/hello/Temporal%20User + http://localhost:3030/hello -You should see "Hello Temporal User!" show on the page which is the result of our -Hello workflow execution. +Enter in first and last name in the form then click on Run Workflow +to start workflow execution. Page will be updated to show the workflow +execution results (the greeting). You can try changing the language setting in [application.yaml](../../../../../../resources/application.yaml) file from "english" to "spanish" to get the greeting result in Spanish. \ No newline at end of file diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java new file mode 100644 index 000000000..d87d8f0f6 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello.model; + +public class Person { + private String firstName; + private String lastName; + + public Person() {} + ; + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/springboot/src/main/resources/templates/hello.html b/springboot/src/main/resources/templates/hello.html new file mode 100644 index 000000000..399bdfe77 --- /dev/null +++ b/springboot/src/main/resources/templates/hello.html @@ -0,0 +1,65 @@ + + + + + + + + + + + + +

+
+
+

Temporal Java SDK Samples

+
This is a simple greeting example. Enter persons first and last name then submit form to start + workflow execution. Results will be updated on the page.
+
+


+
Say hello to:
+
+

First Name:

+

Last Name:

+

+ +

+
+
+
+
+
Workflow result:
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/springboot/src/main/resources/templates/index.html b/springboot/src/main/resources/templates/index.html new file mode 100644 index 000000000..221e96cd9 --- /dev/null +++ b/springboot/src/main/resources/templates/index.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + +
+
+
+
Temporal Java SDK Samples
+

Click on sample link to run it.

+
+ Say Hello +
+
+
+ +
+ + \ No newline at end of file diff --git a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java index 586df5a80..d2eaf41d1 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java @@ -22,6 +22,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.samples.springboot.hello.HelloWorkflow; +import io.temporal.samples.springboot.hello.model.Person; import io.temporal.testing.TestWorkflowEnvironment; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -56,7 +57,7 @@ public void testHello() { .setTaskQueue("HelloSampleTaskQueue") .setWorkflowId("HelloSampleTest") .build()); - String result = workflow.sayHello("Temporal User"); + String result = workflow.sayHello(new Person("Temporal", "User")); Assert.notNull(result, "Greeting should not be null"); Assert.isTrue(result.equals("Hello Temporal User!"), "Invalid result"); } From cb8006fe204541071091b7f9040b2199146ede80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 10:17:54 -0400 Subject: [PATCH 084/240] Bump net.thisptr:jackson-jq (#456) Bumps [net.thisptr:jackson-jq](https://github.com/eiiches/jackson-jq) from 1.0.0-preview.20220705 to 1.0.0-preview.20230409. - [Release notes](https://github.com/eiiches/jackson-jq/releases) - [Commits](https://github.com/eiiches/jackson-jq/compare/1.0.0-preview.20220705...1.0.0-preview.20230409) --- updated-dependencies: - dependency-name: net.thisptr:jackson-jq dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index ae9bd0255..10d7900df 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -31,7 +31,7 @@ dependencies { implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.3.Final' - implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20220705' + implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' From 3b5aa359e6103856170bbab9180a42e60cb85dbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 10:18:23 -0400 Subject: [PATCH 085/240] Bump io.cloudevents:cloudevents-json-jackson from 2.4.2 to 2.5.0 (#458) Bumps io.cloudevents:cloudevents-json-jackson from 2.4.2 to 2.5.0. --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-json-jackson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 10d7900df..4d66ecc9f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -26,7 +26,7 @@ dependencies { implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.2' - implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.4.2' + implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' From 16fabc0200582ace1591b8a0b4850c9f0027cbd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 10:27:09 -0400 Subject: [PATCH 086/240] Bump io.cloudevents:cloudevents-api from 2.4.2 to 2.5.0 (#460) Bumps [io.cloudevents:cloudevents-api](https://github.com/cloudevents/sdk-java) from 2.4.2 to 2.5.0. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.4.2...2.5.0) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4d66ecc9f..681e0c669 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -25,7 +25,7 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' - implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.4.2' + implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' From 51a629f3e2c4203f07838c5d45838c9b55418be6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 10:27:31 -0400 Subject: [PATCH 087/240] Bump com.fasterxml.jackson:jackson-bom from 2.14.2 to 2.15.2 (#462) Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.14.2 to 2.15.2. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.14.2...jackson-bom-2.15.2) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 681e0c669..fa634b4db 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:$javaSDKVersion") // Needed for SDK related functionality - implementation(platform("com.fasterxml.jackson:jackson-bom:2.14.2")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.15.2")) implementation "com.fasterxml.jackson.core:jackson-databind" implementation "com.fasterxml.jackson.core:jackson-core" From 658894f0b16b05f0920ef565acded5a85228f64e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 10:27:55 -0400 Subject: [PATCH 088/240] Bump com.google.errorprone:error_prone_core from 2.18.0 to 2.20.0 (#474) Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.18.0 to 2.20.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.18.0...v2.20.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 4 ++-- springboot/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index fa634b4db..b01b2bfe0 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -47,9 +47,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.18.0') + errorprone('com.google.errorprone:error_prone_core:2.20.0') } else { - errorprone('com.google.errorprone:error_prone_core:2.18.0') + errorprone('com.google.errorprone:error_prone_core:2.20.0') } } } diff --git a/springboot/build.gradle b/springboot/build.gradle index 26fcdc7f6..fbdf56e3f 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -9,9 +9,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.18.0') + errorprone('com.google.errorprone:error_prone_core:2.20.0') } else { - errorprone('com.google.errorprone:error_prone_core:2.18.0') + errorprone('com.google.errorprone:error_prone_core:2.20.0') } } } From be9c49ce53e967babe24356ce2a4bc1a1956609a Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 20 Jun 2023 18:34:09 -0400 Subject: [PATCH 089/240] spring boot samples - sdk metrics (#480) * spring boot samples - sdk metrics Signed-off-by: Tihomir Surdilovic * spelling Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * fix numbering Signed-off-by: Tihomir Surdilovic * update readme Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 1 + springboot/build.gradle | 1 + .../samples/springboot/SamplesController.java | 6 ++ .../samples/springboot/metrics/README.md | 13 +++ .../src/main/resources/application.yaml | 10 ++- .../src/main/resources/templates/index.html | 3 + .../src/main/resources/templates/metrics.html | 86 +++++++++++++++++++ 7 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/metrics/README.md create mode 100644 springboot/src/main/resources/templates/metrics.html diff --git a/README.md b/README.md index f901c8adc..3153238dd 100644 --- a/README.md +++ b/README.md @@ -140,4 +140,5 @@ See the README.md file in each main sample directory for cut/paste Gradle comman More info on each sample: - [**Hello**](/springboot/src/main/java/io/temporal/samples/springboot/hello): Invoke simple "Hello" workflow from a GET endpoint +- [**SDK Metrics**](/springboot/src/main/java/io/temporal/samples/springboot/metrics): Learn how to set up SDK Metrics diff --git a/springboot/build.gradle b/springboot/build.gradle index fbdf56e3f..6d5b7a292 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -5,6 +5,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-thymeleaf" implementation "org.springframework.boot:spring-boot-starter-actuator" implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" + runtimeOnly "io.micrometer:micrometer-registry-prometheus" testImplementation "org.springframework.boot:spring-boot-starter-test" dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index cf18a31c0..888c9d256 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -58,4 +58,10 @@ ResponseEntity helloSample(@RequestBody Person person) { // bypass thymeleaf, don't return template name just result return new ResponseEntity("\"" + workflow.sayHello(person) + "\"", HttpStatus.OK); } + + @GetMapping("/metrics") + public String metrics(Model model) { + model.addAttribute("sample", "SDK Metrics"); + return "metrics"; + } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/metrics/README.md b/springboot/src/main/java/io/temporal/samples/springboot/metrics/README.md new file mode 100644 index 000000000..95a518523 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/metrics/README.md @@ -0,0 +1,13 @@ +# SpringBoot Metrics Sample + +1. Start SpringBoot from main samples repo directory: + + ./gradlew bootRun + +2. In your browser navigate to: + + http://localhost:3030/metrics + +This sample involves just SpringBoot and Actuator configurations which are +included in the samples already. The page shows information on how to set up +SDK metrics in your SpringBoot applications. \ No newline at end of file diff --git a/springboot/src/main/resources/application.yaml b/springboot/src/main/resources/application.yaml index dc13d5ff7..98ae11653 100644 --- a/springboot/src/main/resources/application.yaml +++ b/springboot/src/main/resources/application.yaml @@ -3,6 +3,7 @@ server: spring: application: name: temporal-samples + # temporal specific configs temporal: connection: target: 127.0.0.1:7233 @@ -21,6 +22,13 @@ spring: # max-threads: 10 workersAutoDiscovery: packages: io.temporal.samples.springboot +# actuator (sdk metrics) +management: + endpoints: + web: + exposure: + include: prometheus +# specific for samples samples: data: - language: english \ No newline at end of file + language: english diff --git a/springboot/src/main/resources/templates/index.html b/springboot/src/main/resources/templates/index.html index 221e96cd9..249204725 100644 --- a/springboot/src/main/resources/templates/index.html +++ b/springboot/src/main/resources/templates/index.html @@ -20,6 +20,9 @@
Temporal Java SDK Samples
+ diff --git a/springboot/src/main/resources/templates/metrics.html b/springboot/src/main/resources/templates/metrics.html new file mode 100644 index 000000000..aadca1ba3 --- /dev/null +++ b/springboot/src/main/resources/templates/metrics.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + \ No newline at end of file From d1f41eda6460bd64723372d4bca528a95a4c1078 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 21 Jun 2023 10:04:37 -0700 Subject: [PATCH 090/240] Update Java SDK to v1.20.0 (#482) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6ff4f5dc6..8dd9adc0d 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ subprojects { ext { otelVersion = '1.26.0' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.20.0-SNAPSHOT' + javaSDKVersion = '1.20.0' jarVersion = '1.0.0' } From 80c06694dc3f159cc07d54c0258771a6d1015392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Mon, 26 Jun 2023 06:10:11 +0200 Subject: [PATCH 091/240] add sdk team as codeowner (#484) * add Quinn-With-Two-Ns as codeowner * Update .github/CODEOWNERS Co-authored-by: Chad Retz --------- Co-authored-by: Chad Retz --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a49757761..12855485b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # Primary owners -* @tsurdilo @Spikhalskiy @antmendoza \ No newline at end of file +* @tsurdilo @temporalio/sdk @antmendoza \ No newline at end of file From 307a2df3e5adc269fb21d8a7e8afdd001d9ef72d Mon Sep 17 00:00:00 2001 From: Aymalla Date: Mon, 26 Jun 2023 05:10:31 +0100 Subject: [PATCH 092/240] SSL-enabled WorkflowClient with CA cert as param and overriding authority name (#448) * Ssl enabled worker custom CA and authority name * Update README.md * rebase to main branch * update readme --- .../java/io/temporal/samples/ssl/README.md | 44 +++++- .../samples/ssl/SslEnabledWorkerCustomCA.java | 134 ++++++++++++++++++ 2 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java diff --git a/core/src/main/java/io/temporal/samples/ssl/README.md b/core/src/main/java/io/temporal/samples/ssl/README.md index 187b5cc46..a48d7aedf 100644 --- a/core/src/main/java/io/temporal/samples/ssl/README.md +++ b/core/src/main/java/io/temporal/samples/ssl/README.md @@ -1,11 +1,11 @@ # Workflow execution with mTLS - This example shows how to secure your Temporal application with [mTLS](https://docs.temporal.io/security/#encryption-in-transit-with-mtls). This is required to connect with Temporal Cloud or any production Temporal deployment. ## Export env variables + Before running the example you need to export the following env variables: - TEMPORAL_ENDPOINT: grpc endpoint, for Temporal Cloud would like `${namespace}.tmprl.cloud:7233`. @@ -13,10 +13,48 @@ Before running the example you need to export the following env variables: - TEMPORAL_CLIENT_CERT: For Temporal Cloud see requirements [here](https://docs.temporal.io/cloud/how-to-manage-certificates-in-temporal-cloud#end-entity-certificates). - TEMPORAL_CLIENT_KEY: For Temporal Cloud see requirements [here](https://docs.temporal.io/cloud/how-to-manage-certificates-in-temporal-cloud#end-entity-certificates). - - ## Running this sample ```bash ./gradlew -q execute -PmainClass=io.temporal.samples.ssl.Starter ``` + +## Run SslEnabledWorkerCustomCA Sample + +This sample shows how to start a worker that connects to a temporal cluster with mTLS enabled; created by ([tls-simple sample](https://github.com/temporalio/samples-server/tree/main/tls/tls-simple)); + +SslEnabledWorkerCustomCA demonstrates: + +- Passing a custom CA certificate file as parameter +- Overriding the authority name used for TLS handshakes (if needed) + +1.Start a temporal cluster with tls + +Please follow the temporal server-sample to start simple Temporal mTLS cluster locally: [tls-simple](https://github.com/temporalio/samples-server/tree/main/tls/tls-simple) + +2.Set environment variables + +```bash +# Environment variables +# paths to ca cert, client cert and client key come from the previous step +export TEMPORAL_CLIENT_CERT="" +export TEMPORAL_CLIENT_KEY="" +export TEMPORAL_CA_CERT="" +export TEMPORAL_ENDPOINT="localhost:7233" # Temporal grpc endpoint +export TEMPORAL_NAMESPACE="default" # Temporal namespace +export TEMPORAL_SERVER_HOSTNAME="tls-sample" # Temporal server host name +``` + +3.Start the Worker + +```bash +./gradlew -q execute -PmainClass="io.temporal.samples.ssl.SslEnabledWorkerCustomCA" +``` + +4.Expected result + +```text +[main] INFO i.t.s.WorkflowServiceStubsImpl - Created WorkflowServiceStubs for channel: ManagedChannelOrphanWrapper{delegate=ManagedChannelImpl{logId=1, target=localhost:7233}} +[main] INFO io.temporal.internal.worker.Poller - start: Poller{name=Workflow Poller taskQueue="MyTaskQueue", namespace="default"} +Workflow completed:done +``` diff --git a/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java b/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java new file mode 100644 index 000000000..165737ffa --- /dev/null +++ b/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.ssl; + +import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import java.io.FileInputStream; +import java.io.InputStream; + +public class SslEnabledWorkerCustomCA { + + static final String TASK_QUEUE = "MyTaskQueue"; + + public static void main(String[] args) throws Exception { + + // Load your client certificate, which should look like: + // -----BEGIN CERTIFICATE----- + // ... + // -----END CERTIFICATE----- + InputStream clientCert = new FileInputStream(System.getenv("TEMPORAL_CLIENT_CERT")); + + // PKCS8 client key, which should look like: + // -----BEGIN PRIVATE KEY----- + // ... + // -----END PRIVATE KEY----- + InputStream clientKey = new FileInputStream(System.getenv("TEMPORAL_CLIENT_KEY")); + + // Load your Certification Authority certificate, which should look like: + // -----BEGIN CERTIFICATE----- + // ... + // -----END CERTIFICATE----- + InputStream caCert = new FileInputStream(System.getenv("TEMPORAL_CA_CERT")); + + // For temporal cloud this would likely be ${namespace}.tmprl.cloud:7233 + String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT"); + + // Your registered namespace. + String namespace = System.getenv("TEMPORAL_NAMESPACE"); + + // Create an SSL Context using the client certificate and key based on the implementation + // SimpleSslContextBuilder + // https://github.com/temporalio/sdk-java/blob/master/temporal-serviceclient/src/main/java/io/temporal/serviceclient/SimpleSslContextBuilder.java + SslContext sslContext = + GrpcSslContexts.configure( + SslContextBuilder.forClient() + .keyManager(clientCert, clientKey) + .trustManager(caCert)) + .build(); + + // Create SSL enabled client by passing SslContext, created by + // SimpleSslContextBuilder. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs( + WorkflowServiceStubsOptions.newBuilder() + .setSslContext(sslContext) + .setTarget(targetEndpoint) + // Override the authority name used for TLS handshakes + .setChannelInitializer( + c -> c.overrideAuthority(System.getenv("TEMPORAL_SERVER_HOSTNAME"))) + .build()); + + // Now setup and start workflow worker, which uses SSL enabled gRPC service to + // communicate with backend. client that can be used to start and signal workflows. + WorkflowClient client = + WorkflowClient.newInstance( + service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build()); + + // worker factory that can be used to create workers for specific task queues + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register our workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + // Create the workflow client stub. It is used to start our workflow execution. + MyWorkflow workflow = + client.newWorkflowStub( + MyWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId("WORKFLOW_ID") + .setTaskQueue(TASK_QUEUE) + .build()); + + /* + * Execute our workflow and wait for it to complete. The call to our execute method is + * synchronous. + */ + String greeting = workflow.execute(); + + // Display workflow execution results + System.out.println("Workflow completed:" + greeting); + System.exit(0); + } +} From b7c642a58754c88f14e19d7140c16b26c2110fab Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 27 Jun 2023 23:01:03 -0400 Subject: [PATCH 093/240] SpringBoot - Sync Update Example (#490) * SpringBoot - Sync Update Example Signed-off-by: Tihomir Surdilovic * fix text Signed-off-by: Tihomir Surdilovic * update - move local activity calls from update handler Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 1 + springboot/build.gradle | 2 + .../samples/springboot/SamplesController.java | 59 ++++++++ .../springboot/hello/model/Person.java | 1 - ...ProductNotAvailableForAmountException.java | 26 ++++ .../springboot/update/PurchaseActivities.java | 30 ++++ .../update/PurchaseActivitiesImpl.java | 59 ++++++++ .../springboot/update/PurchaseWorkflow.java | 38 ++++++ .../update/PurchaseWorkflowImpl.java | 82 +++++++++++ .../samples/springboot/update/README.md | 35 +++++ .../update/ResourceNotFoundException.java | 30 ++++ .../springboot/update/model/Product.java | 129 ++++++++++++++++++ .../update/model/ProductRepository.java | 26 ++++ .../springboot/update/model/Purchase.java | 48 +++++++ .../src/main/resources/application.yaml | 15 ++ springboot/src/main/resources/data.sql | 5 + .../main/resources/templates/fragments.html | 21 +++ .../src/main/resources/templates/hello.html | 13 +- .../src/main/resources/templates/index.html | 16 +-- .../src/main/resources/templates/metrics.html | 13 +- .../src/main/resources/templates/update.html | 125 +++++++++++++++++ .../samples/springboot/HelloUpdateTest.java | 91 ++++++++++++ .../src/test/resources/application.yaml | 16 ++- springboot/src/test/resources/data.sql | 5 + 24 files changed, 850 insertions(+), 36 deletions(-) create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/ProductNotAvailableForAmountException.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivities.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivitiesImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflow.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflowImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/README.md create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/ResourceNotFoundException.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/model/Product.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/model/ProductRepository.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/update/model/Purchase.java create mode 100644 springboot/src/main/resources/data.sql create mode 100644 springboot/src/main/resources/templates/fragments.html create mode 100644 springboot/src/main/resources/templates/update.html create mode 100644 springboot/src/test/java/io/temporal/samples/springboot/HelloUpdateTest.java create mode 100644 springboot/src/test/resources/data.sql diff --git a/README.md b/README.md index 3153238dd..e0b6dc4fa 100644 --- a/README.md +++ b/README.md @@ -141,4 +141,5 @@ See the README.md file in each main sample directory for cut/paste Gradle comman More info on each sample: - [**Hello**](/springboot/src/main/java/io/temporal/samples/springboot/hello): Invoke simple "Hello" workflow from a GET endpoint - [**SDK Metrics**](/springboot/src/main/java/io/temporal/samples/springboot/metrics): Learn how to set up SDK Metrics +- [**Synchronous Update**](/springboot/src/main/java/io/temporal/samples/springboot/update): Learn how to use Synchronous Update feature with this purchase sample diff --git a/springboot/build.gradle b/springboot/build.gradle index 6d5b7a292..ba091d9f3 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -4,8 +4,10 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-web" implementation "org.springframework.boot:spring-boot-starter-thymeleaf" implementation "org.springframework.boot:spring-boot-starter-actuator" + implementation "org.springframework.boot:spring-boot-starter-data-jpa" implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" runtimeOnly "io.micrometer:micrometer-registry-prometheus" + runtimeOnly "com.h2database:h2" testImplementation "org.springframework.boot:spring-boot-starter-test" dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index 888c9d256..7f0d65e26 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -19,10 +19,16 @@ package io.temporal.samples.springboot; +import io.grpc.StatusRuntimeException; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.client.WorkflowUpdateException; import io.temporal.samples.springboot.hello.HelloWorkflow; import io.temporal.samples.springboot.hello.model.Person; +import io.temporal.samples.springboot.update.PurchaseWorkflow; +import io.temporal.samples.springboot.update.model.ProductRepository; +import io.temporal.samples.springboot.update.model.Purchase; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -36,6 +42,8 @@ public class SamplesController { @Autowired WorkflowClient client; + @Autowired ProductRepository productRepository; + @GetMapping("/hello") public String hello(Model model) { model.addAttribute("sample", "Say Hello"); @@ -64,4 +72,55 @@ public String metrics(Model model) { model.addAttribute("sample", "SDK Metrics"); return "metrics"; } + + @GetMapping("/update") + public String update(Model model) { + model.addAttribute("sample", "Synchronous Update"); + model.addAttribute("products", productRepository.findAll()); + return "update"; + } + + @GetMapping("/update/inventory") + public String updateInventory(Model model) { + model.addAttribute("products", productRepository.findAll()); + return "update :: inventory"; + } + + @PostMapping( + value = "/update/purchase", + consumes = {MediaType.APPLICATION_JSON_VALUE}, + produces = {MediaType.TEXT_HTML_VALUE}) + ResponseEntity purchase(@RequestBody Purchase purchase) { + PurchaseWorkflow workflow = + client.newWorkflowStub( + PurchaseWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("UpdateSampleTaskQueue") + .setWorkflowId("NewPurchase") + .build()); + WorkflowClient.start(workflow::start); + + // send update + try { + boolean isValidPurchase = workflow.makePurchase(purchase); + // for sample send exit to workflow exec and wait till it completes + workflow.exit(); + WorkflowStub.fromTyped(workflow).getResult(Void.class); + if (!isValidPurchase) { + return new ResponseEntity("\"Invalid purchase\"", HttpStatus.NOT_FOUND); + } + return new ResponseEntity("\"" + "Purchase successful" + "\"", HttpStatus.OK); + } catch (WorkflowUpdateException | StatusRuntimeException e) { + // for sample send exit to workflow exec and wait till it completes + workflow.exit(); + WorkflowStub.fromTyped(workflow).getResult(Void.class); + + String message = e.getMessage(); + if (e instanceof WorkflowUpdateException) { + message = e.getCause().getMessage(); + } + + return new ResponseEntity("\"" + message + "\"", HttpStatus.NOT_FOUND); + } + } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java index d87d8f0f6..c71862b23 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java @@ -24,7 +24,6 @@ public class Person { private String lastName; public Person() {} - ; public Person(String firstName, String lastName) { this.firstName = firstName; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/ProductNotAvailableForAmountException.java b/springboot/src/main/java/io/temporal/samples/springboot/update/ProductNotAvailableForAmountException.java new file mode 100644 index 000000000..56ce54e4a --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/ProductNotAvailableForAmountException.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update; + +public class ProductNotAvailableForAmountException extends Exception { + public ProductNotAvailableForAmountException(String message) { + super(message); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivities.java b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivities.java new file mode 100644 index 000000000..8be9aa256 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivities.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update; + +import io.temporal.activity.ActivityInterface; +import io.temporal.samples.springboot.update.model.Purchase; + +@ActivityInterface +public interface PurchaseActivities { + boolean isProductInStockForPurchase(Purchase purchase); + + boolean makePurchase(Purchase purchase); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivitiesImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivitiesImpl.java new file mode 100644 index 000000000..4f0596d59 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivitiesImpl.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update; + +import io.temporal.samples.springboot.update.model.Product; +import io.temporal.samples.springboot.update.model.ProductRepository; +import io.temporal.samples.springboot.update.model.Purchase; +import io.temporal.spring.boot.ActivityImpl; +import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@ActivityImpl(taskQueues = "UpdateSampleTaskQueue") +public class PurchaseActivitiesImpl implements PurchaseActivities { + @Autowired ProductRepository productRepository; + + @Override + public boolean isProductInStockForPurchase(Purchase purchase) { + Product product = getProductFor(purchase); + return product != null && product.getStock() >= purchase.getAmount(); + } + + @Override + public boolean makePurchase(Purchase purchase) { + Product product = getProductFor(purchase); + if (product != null) { + product.setStock(product.getStock() - purchase.getAmount()); + productRepository.save(product); + return true; + } + return false; + } + + private Product getProductFor(Purchase purchase) { + Optional productOptional = productRepository.findById(purchase.getProduct()); + if (productOptional.isPresent()) { + return productOptional.get(); + } + return null; + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflow.java new file mode 100644 index 000000000..d5f086683 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflow.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update; + +import io.temporal.samples.springboot.update.model.Purchase; +import io.temporal.workflow.*; + +@WorkflowInterface +public interface PurchaseWorkflow { + @WorkflowMethod + void start(); + + @UpdateMethod + boolean makePurchase(Purchase purchase); + + @UpdateValidatorMethod(updateName = "makePurchase") + void makePurchaseValidator(Purchase purchase); + + @SignalMethod + void exit(); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflowImpl.java new file mode 100644 index 000000000..bc04b3f41 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflowImpl.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update; + +import io.temporal.activity.LocalActivityOptions; +import io.temporal.failure.ApplicationFailure; +import io.temporal.samples.springboot.update.model.Purchase; +import io.temporal.spring.boot.WorkflowImpl; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +@WorkflowImpl(taskQueues = "UpdateSampleTaskQueue") +public class PurchaseWorkflowImpl implements PurchaseWorkflow { + + private boolean newPurchase = false; + private boolean exit = false; + private PurchaseActivities activities = + Workflow.newLocalActivityStub( + PurchaseActivities.class, + LocalActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public void start() { + // for sake of sample we only wait for a single purchase or exit signal + Workflow.await(() -> newPurchase || exit); + } + + @Override + public boolean makePurchase(Purchase purchase) { + + if (!activities.isProductInStockForPurchase(purchase)) { + throw ApplicationFailure.newFailure( + "Product " + + purchase.getProduct() + + " is not in stock for amount " + + purchase.getAmount(), + ProductNotAvailableForAmountException.class.getName(), + purchase); + } + + return activities.makePurchase(purchase); + } + + @Override + public void makePurchaseValidator(Purchase purchase) { + // Not allowed to change workflow state inside validator + // So invocations of (local) activities is prohibited + // We can validate the purchase with some business logic here + + // Assume we have some max inventory amount for single item set to 100 + if (purchase == null || (purchase.getAmount() < 0 || purchase.getAmount() > 100)) { + throw new IllegalArgumentException( + "Invalid Product or amount (Product id:" + + purchase.getProduct() + + ", amount" + + purchase.getAmount() + + ")"); + } + } + + @Override + public void exit() { + this.exit = true; + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/README.md b/springboot/src/main/java/io/temporal/samples/springboot/update/README.md new file mode 100644 index 000000000..fdeaba18a --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/README.md @@ -0,0 +1,35 @@ +# SpringBoot Synchronous Update Sample + +1. Start SpringBoot from main samples repo directory: + + ./gradlew bootRun + +2. In your browser navigate to: + + http://localhost:3030/update + +Pick one of the fishing items you want to purchase from the inventory drop down list. +Next pick the amount of this item you want to purchase. +The inventory is presented in the table below the form. +For each item you can see the current availble stock count. +Try first picking an item and then an amount that is less or equal to the items in +inventory. You will see that the purchase goes through and the inventory table is updated +dynamically. + +Now try to pick and item and amount that is greater than what's in our inventory. +You will see that the update fails and you see the "Unable to perform purchase" +message that shows the underlying "ProductNotAvailableForAmountException" exception +raised in the update handler. + +Updating our inventory is done via local activities. The check if item and amount +of the fishing item you want to purchase is in inventory is also done by local +activity. + +## Note +Make sure that you enable the synchronous update feature on your Temporal cluster. +This can be done in dynamic config with + + frontend.enableUpdateWorkflowExecution: + - value: true + +If you don't have this enabled you will see error shown when you try to make any purchase. \ No newline at end of file diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/ResourceNotFoundException.java b/springboot/src/main/java/io/temporal/samples/springboot/update/ResourceNotFoundException.java new file mode 100644 index 000000000..21cfc71ac --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/ResourceNotFoundException.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(value = HttpStatus.NOT_FOUND) +public class ResourceNotFoundException extends Exception { + public ResourceNotFoundException(String message) { + super(message); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/model/Product.java b/springboot/src/main/java/io/temporal/samples/springboot/update/model/Product.java new file mode 100644 index 000000000..74e39b7b3 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/model/Product.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update.model; + +import javax.persistence.*; + +@Entity +public class Product { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(nullable = false) + public String name; + + @Column(nullable = false) + public String code; + + @Column(nullable = false) + public String description; + + @Column(nullable = false) + public int price = 0; + + @Column(nullable = false) + private int stock = 20; + + public Product() {} + + public Product(Integer id, String name, String code, String description, int price, int stock) { + this.id = id; + this.name = name; + this.code = code; + this.description = description; + this.price = price; + this.stock = stock; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public int getPrice() { + return price; + } + + public void setPrice(int price) { + this.price = price; + } + + public int getStock() { + return stock; + } + + public void setStock(int stock) { + this.stock = stock; + } + + public boolean removeStock() { + if (this.stock > 0) { + this.stock--; + return true; + } else { + return false; + } + } + + public boolean removeStock(int value) { + if (this.stock > 0) { + this.stock -= value; + return true; + } else { + return false; + } + } + + public void addStock() { + this.stock++; + } + + public void addStock(int value) { + this.stock += value; + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/model/ProductRepository.java b/springboot/src/main/java/io/temporal/samples/springboot/update/model/ProductRepository.java new file mode 100644 index 000000000..5d8d2dd99 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/model/ProductRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update.model; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ProductRepository extends JpaRepository {} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/model/Purchase.java b/springboot/src/main/java/io/temporal/samples/springboot/update/model/Purchase.java new file mode 100644 index 000000000..3457c65a4 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/model/Purchase.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.update.model; + +public class Purchase { + int product; + int amount; + + public Purchase() {} + + public Purchase(int product, int amount) { + this.product = product; + this.amount = amount; + } + + public int getProduct() { + return product; + } + + public void setProduct(int product) { + this.product = product; + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } +} diff --git a/springboot/src/main/resources/application.yaml b/springboot/src/main/resources/application.yaml index 98ae11653..a6177bde4 100644 --- a/springboot/src/main/resources/application.yaml +++ b/springboot/src/main/resources/application.yaml @@ -22,6 +22,21 @@ spring: # max-threads: 10 workersAutoDiscovery: packages: io.temporal.samples.springboot + # data source config for some samples that need it + datasource: + url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false; + username: sa + password: pass + driver-class-name: org.h2.Driver + jpa: + database-platform: org.hibernate.dialect.H2Dialect + hibernate: + ddl-auto: create-drop + defer-datasource-initialization: true + ## enable h2 console (h2-console endpoint) for debugging + h2: + console: + enabled: true # actuator (sdk metrics) management: endpoints: diff --git a/springboot/src/main/resources/data.sql b/springboot/src/main/resources/data.sql new file mode 100644 index 000000000..cd2d206c6 --- /dev/null +++ b/springboot/src/main/resources/data.sql @@ -0,0 +1,5 @@ +INSERT INTO product(name, code, description, price, stock) VALUES ('Zoom U-Tale Worm', 'w1', 'The U-Tale Worms are another one of Zooms truly-impressive big bass baits.', 5, 20); +INSERT INTO product(name, code, description, price, stock) VALUES ('Yamamoto Baits 5" Senko', 'w2', 'Yamamoto Baits 5" Senko has become a mainstay for bass throughout the United States.', 7, 15); +INSERT INTO product(name, code, description, price, stock) VALUES ('Rapala Original Floating Minnow', 'w3', 'The Rapala Original Floating Minnow is the lure that started it all and is still one of the most popular lures around.', 10, 10); +INSERT INTO product(name, code, description, price, stock) VALUES ('Z-Man Jackhammer', 'w4', 'Exclusive patented ChatterBait bladed swim jig design and stainless hex-shaped ChatterBlade.', 18, 10); +INSERT INTO product(name, code, description, price, stock) VALUES ('Roboworm Straight Tail Worm Bait', 'w5', 'Roboworms are the most consistant poured baits on the market.', 9, 30); \ No newline at end of file diff --git a/springboot/src/main/resources/templates/fragments.html b/springboot/src/main/resources/templates/fragments.html new file mode 100644 index 000000000..29b0a1ff1 --- /dev/null +++ b/springboot/src/main/resources/templates/fragments.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/springboot/src/main/resources/templates/hello.html b/springboot/src/main/resources/templates/hello.html index 399bdfe77..8bf6b7f0c 100644 --- a/springboot/src/main/resources/templates/hello.html +++ b/springboot/src/main/resources/templates/hello.html @@ -1,16 +1,6 @@ - - - - - - - - - +
@@ -61,5 +51,6 @@
Workflow result:
}); }); +
\ No newline at end of file diff --git a/springboot/src/main/resources/templates/index.html b/springboot/src/main/resources/templates/index.html index 249204725..8b4ab28fe 100644 --- a/springboot/src/main/resources/templates/index.html +++ b/springboot/src/main/resources/templates/index.html @@ -1,16 +1,6 @@ - - - - - - - - - +
@@ -23,9 +13,11 @@
Temporal Java SDK Samples
+
-
\ No newline at end of file diff --git a/springboot/src/main/resources/templates/metrics.html b/springboot/src/main/resources/templates/metrics.html index aadca1ba3..ee7267bef 100644 --- a/springboot/src/main/resources/templates/metrics.html +++ b/springboot/src/main/resources/templates/metrics.html @@ -1,16 +1,6 @@ - - - - - - - - - +
@@ -82,5 +72,6 @@
4. View metrics (Prometheus format)
+
\ No newline at end of file diff --git a/springboot/src/main/resources/templates/update.html b/springboot/src/main/resources/templates/update.html new file mode 100644 index 000000000..843ba8b10 --- /dev/null +++ b/springboot/src/main/resources/templates/update.html @@ -0,0 +1,125 @@ + + + + +
+
+
+

Temporal Java SDK Samples

+
This sample shows use of Synchronous Update feature. The page shows a form used to make a purchase. +
Under the form you can see the total inventory of our fishing items. + Inventory has a pre-set stock (number of each item available). Once you make a purchase our workflow + is sent an update, meaning we want to make the purchase and respond back when its done. +
The workflow update validator checks if the given amount of an item is still available in the inventory. +
If it is then the update goes through and the inventory table is dynamically updated. + If not then the update is rejected and shown on the screen.
+
+
+
+
+

Purchase Form

+
+
+

Select product: + +

+ + +
+

+

+
+
+ +
+
+

+

Inventory

+
+ + + + + + + + + + + + + + + + + + + +
IdNameDescriptionPrice ($)Stock (Available)
IdNameDescriptionPriceStock
+
+
+
+
+
+
+
+ +
+ + \ No newline at end of file diff --git a/springboot/src/test/java/io/temporal/samples/springboot/HelloUpdateTest.java b/springboot/src/test/java/io/temporal/samples/springboot/HelloUpdateTest.java new file mode 100644 index 000000000..c71027f8e --- /dev/null +++ b/springboot/src/test/java/io/temporal/samples/springboot/HelloUpdateTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import io.temporal.client.*; +import io.temporal.samples.springboot.update.PurchaseWorkflow; +import io.temporal.samples.springboot.update.model.Purchase; +import io.temporal.testing.TestWorkflowEnvironment; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootTest(classes = HelloUpdateTest.Configuration.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class HelloUpdateTest { + + @Autowired ConfigurableApplicationContext applicationContext; + + @Autowired TestWorkflowEnvironment testWorkflowEnvironment; + + @Autowired WorkflowClient workflowClient; + + @BeforeEach + void setUp() { + applicationContext.start(); + } + + @Test + public void testUpdate() { + PurchaseWorkflow workflow = + workflowClient.newWorkflowStub( + PurchaseWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("UpdateSampleTaskQueue") + .setWorkflowId("NewPurchase") + .build()); + Purchase purchase = new Purchase(1, 3); + WorkflowClient.start(workflow::start); + // send update + workflow.makePurchase(purchase); + workflow.exit(); + WorkflowStub.fromTyped(workflow).getResult(Void.class); + } + + @Test() + public void testUpdateRejected() { + PurchaseWorkflow workflow = + workflowClient.newWorkflowStub( + PurchaseWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("UpdateSampleTaskQueue") + .setWorkflowId("NewPurchase") + .build()); + Purchase purchase = new Purchase(1, 40); + WorkflowClient.start(workflow::start); + // send update + assertThrows( + WorkflowUpdateException.class, + () -> { + workflow.makePurchase(purchase); + }); + workflow.exit(); + WorkflowStub.fromTyped(workflow).getResult(Void.class); + } + + @ComponentScan + public static class Configuration {} +} diff --git a/springboot/src/test/resources/application.yaml b/springboot/src/test/resources/application.yaml index 95ab48335..931aa0a86 100644 --- a/springboot/src/test/resources/application.yaml +++ b/springboot/src/test/resources/application.yaml @@ -3,14 +3,28 @@ server: spring: application: name: temporal-samples + # temporal specific configs temporal: connection: target: 127.0.0.1:7233 target.namespace: default workersAutoDiscovery: packages: io.temporal.samples.springboot + # enable test server for testing test-server: enabled: true + # data source config for tests that need it + datasource: + url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;DB_CLOSE_ON_EXIT=FALSE; + username: sa + password: pass + driver-class-name: org.h2.Driver + jpa: + database-platform: org.hibernate.dialect.H2Dialect + hibernate: + ddl-auto: create-drop + defer-datasource-initialization: true +# specific for samples samples: data: - language: english \ No newline at end of file + language: english diff --git a/springboot/src/test/resources/data.sql b/springboot/src/test/resources/data.sql new file mode 100644 index 000000000..cd2d206c6 --- /dev/null +++ b/springboot/src/test/resources/data.sql @@ -0,0 +1,5 @@ +INSERT INTO product(name, code, description, price, stock) VALUES ('Zoom U-Tale Worm', 'w1', 'The U-Tale Worms are another one of Zooms truly-impressive big bass baits.', 5, 20); +INSERT INTO product(name, code, description, price, stock) VALUES ('Yamamoto Baits 5" Senko', 'w2', 'Yamamoto Baits 5" Senko has become a mainstay for bass throughout the United States.', 7, 15); +INSERT INTO product(name, code, description, price, stock) VALUES ('Rapala Original Floating Minnow', 'w3', 'The Rapala Original Floating Minnow is the lure that started it all and is still one of the most popular lures around.', 10, 10); +INSERT INTO product(name, code, description, price, stock) VALUES ('Z-Man Jackhammer', 'w4', 'Exclusive patented ChatterBait bladed swim jig design and stainless hex-shaped ChatterBlade.', 18, 10); +INSERT INTO product(name, code, description, price, stock) VALUES ('Roboworm Straight Tail Worm Bait', 'w5', 'Roboworms are the most consistant poured baits on the market.', 9, 30); \ No newline at end of file From d9d6bd3ab59971d099644378433aab2e4f88ed1a Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Fri, 30 Jun 2023 10:05:11 -0400 Subject: [PATCH 094/240] SpringBoot - Kafka Sample (#493) * SpringBoot - Kafka Sample Signed-off-by: Tihomir Surdilovic * add comment on tests Signed-off-by: Tihomir Surdilovic * small fix for test Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- build.gradle | 3 +- springboot/build.gradle | 3 + .../samples/springboot/SamplesController.java | 29 +++ .../springboot/kafka/KafkaActivity.java | 27 +++ .../springboot/kafka/KafkaActivityImpl.java | 44 ++++ .../samples/springboot/kafka/KafkaConfig.java | 77 +++++++ .../springboot/kafka/MessageController.java | 52 +++++ .../springboot/kafka/MessageWorkflow.java | 34 +++ .../springboot/kafka/MessageWorkflowImpl.java | 54 +++++ .../samples/springboot/kafka/README.md | 32 +++ .../src/main/resources/application.yaml | 12 ++ .../main/resources/static/js/jquery.sse.js | 199 ++++++++++++++++++ .../main/resources/static/js/samplessse.js | 18 ++ .../src/main/resources/templates/index.html | 3 + .../src/main/resources/templates/kafka.html | 65 ++++++ .../samples/springboot/HelloSampleTest.java | 8 + .../springboot/KafkaConsumerTestHelper.java | 50 +++++ .../samples/springboot/KafkaSampleTest.java | 83 ++++++++ ...oUpdateTest.java => UpdateSampleTest.java} | 12 +- .../src/test/resources/application.yaml | 12 ++ 20 files changed, 814 insertions(+), 3 deletions(-) create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivity.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaConfig.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflow.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflowImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/kafka/README.md create mode 100644 springboot/src/main/resources/static/js/jquery.sse.js create mode 100644 springboot/src/main/resources/static/js/samplessse.js create mode 100644 springboot/src/main/resources/templates/kafka.html create mode 100644 springboot/src/test/java/io/temporal/samples/springboot/KafkaConsumerTestHelper.java create mode 100644 springboot/src/test/java/io/temporal/samples/springboot/KafkaSampleTest.java rename springboot/src/test/java/io/temporal/samples/springboot/{HelloUpdateTest.java => UpdateSampleTest.java} (85%) diff --git a/build.gradle b/build.gradle index 8dd9adc0d..30336802d 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.1.0" id 'com.diffplug.spotless' version '6.17.0' apply false - id 'org.springframework.boot' version '2.7.12' + id 'org.springframework.boot' version '2.7.13' } subprojects { @@ -39,6 +39,7 @@ subprojects { exclude '**/*.yaml' exclude '**/*.yml' exclude '**/*.html' + exclude '**/*.js' } if (JavaVersion.current().isJava11Compatible()) { diff --git a/springboot/build.gradle b/springboot/build.gradle index ba091d9f3..4adb212c5 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -5,6 +5,9 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-thymeleaf" implementation "org.springframework.boot:spring-boot-starter-actuator" implementation "org.springframework.boot:spring-boot-starter-data-jpa" + implementation "org.springframework.kafka:spring-kafka" + // we set this as impl depends to use embedded kafka in samples not just tests + implementation "org.springframework.kafka:spring-kafka-test" implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" runtimeOnly "io.micrometer:micrometer-registry-prometheus" runtimeOnly "com.h2database:h2" diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index 7f0d65e26..006049096 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -26,6 +26,7 @@ import io.temporal.client.WorkflowUpdateException; import io.temporal.samples.springboot.hello.HelloWorkflow; import io.temporal.samples.springboot.hello.model.Person; +import io.temporal.samples.springboot.kafka.MessageWorkflow; import io.temporal.samples.springboot.update.PurchaseWorkflow; import io.temporal.samples.springboot.update.model.ProductRepository; import io.temporal.samples.springboot.update.model.Purchase; @@ -123,4 +124,32 @@ ResponseEntity purchase(@RequestBody Purchase purchase) { return new ResponseEntity("\"" + message + "\"", HttpStatus.NOT_FOUND); } } + + @GetMapping("/kafka") + public String afka(Model model) { + model.addAttribute("sample", "Kafka Request / Reply"); + return "kafka"; + } + + @PostMapping( + value = "/kafka", + consumes = {MediaType.TEXT_PLAIN_VALUE}, + produces = {MediaType.TEXT_HTML_VALUE}) + ResponseEntity sendToKafka(@RequestBody String message) { + MessageWorkflow workflow = + client.newWorkflowStub( + MessageWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("KafkaSampleTaskQueue") + .setWorkflowId("MessageSample") + .build()); + + WorkflowClient.start(workflow::start); + workflow.update(message); + + // wait till exec completes + WorkflowStub.fromTyped(workflow).getResult(Void.class); + // bypass thymeleaf, don't return template name just result + return new ResponseEntity("\" Message workflow completed\"", HttpStatus.OK); + } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivity.java new file mode 100644 index 000000000..9a6933497 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivity.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.kafka; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface KafkaActivity { + void sendMessage(String message); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java new file mode 100644 index 000000000..8b9b4c781 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.kafka; + +import io.temporal.spring.boot.ActivityImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +@Component +@ActivityImpl(taskQueues = "KafkaSampleTaskQueue") +public class KafkaActivityImpl implements KafkaActivity { + + // Setting required to false means we won't fail + // if a test does not have kafka enabled + @Autowired(required = false) + private KafkaTemplate kafkaTemplate; + + @Value(value = "${samples.message.topic.name}") + private String topicName; + + @Override + public void sendMessage(String message) { + kafkaTemplate.send(topicName, message); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaConfig.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaConfig.java new file mode 100644 index 000000000..30b07d1bb --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaConfig.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.kafka; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.core.KafkaAdmin; +import org.springframework.kafka.test.EmbeddedKafkaBroker; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +@Configuration() +@Profile("!test") +public class KafkaConfig { + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapAddress; + + @Value(value = "${samples.message.topic.name}") + private String topicName; + + @Autowired private MessageController messageController; + + @Bean + EmbeddedKafkaBroker broker() { + return new EmbeddedKafkaBroker(1) + .kafkaPorts(9092) + .brokerListProperty("spring.kafka.bootstrap-servers"); + } + + @Bean + public KafkaAdmin kafkaAdmin() { + Map configs = new HashMap<>(); + configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + return new KafkaAdmin(configs); + } + + @Bean + public NewTopic samplesTopic() { + return new NewTopic(topicName, 1, (short) 1); + } + + @KafkaListener(id = "samples-topic", topics = "samples-topic") + public void kafkaListener(String message) { + SseEmitter latestEm = messageController.getLatestEmitter(); + + try { + latestEm.send(message); + } catch (IOException e) { + latestEm.completeWithError(e); + } + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java new file mode 100644 index 000000000..8ba518fee --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.kafka; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +@RestController +public class MessageController { + private final List emitters = new ArrayList<>(); + + @GetMapping("/kafka-messages") + public SseEmitter getKafkaMessages() { + + SseEmitter emitter = new SseEmitter(60 * 1000L); + emitters.add(emitter); + + emitter.onCompletion(() -> emitters.remove(emitter)); + + emitter.onTimeout(() -> emitters.remove(emitter)); + + return emitter; + } + + public List getEmitters() { + return emitters; + } + + public SseEmitter getLatestEmitter() { + return (emitters.isEmpty()) ? null : emitters.get(emitters.size() - 1); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflow.java new file mode 100644 index 000000000..866482b71 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflow.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.kafka; + +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface MessageWorkflow { + + @WorkflowMethod + void start(); + + @SignalMethod + void update(String message); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflowImpl.java new file mode 100644 index 000000000..8aef1a9c9 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflowImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.kafka; + +import io.temporal.activity.ActivityOptions; +import io.temporal.spring.boot.WorkflowImpl; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +@WorkflowImpl(taskQueues = "KafkaSampleTaskQueue") +public class MessageWorkflowImpl implements MessageWorkflow { + + private KafkaActivity activity = + Workflow.newActivityStub( + KafkaActivity.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + private String message = null; + + @Override + public void start() { + Workflow.await(() -> message != null); + // simulate some steps / milestones + activity.sendMessage( + "Starting execution: " + Workflow.getInfo().getWorkflowId() + " with message: " + message); + + activity.sendMessage("Step 1 done..."); + activity.sendMessage("Step 2 done..."); + activity.sendMessage("Step 3 done..."); + + activity.sendMessage("Completing execution: " + Workflow.getInfo().getWorkflowId()); + } + + @Override + public void update(String message) { + this.message = message; + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/README.md b/springboot/src/main/java/io/temporal/samples/springboot/kafka/README.md new file mode 100644 index 000000000..1c9dc8c71 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/README.md @@ -0,0 +1,32 @@ +# SpringBoot Kafka Request / Reply Sample + +1. Start SpringBoot from main samples repo directory: + + ./gradlew bootRun + +2. In your browser navigate to: + + http://localhost:3030/kafka + +## Use Case +When you start adopting Temporal in your existing applications it can +very often become a much better replacement to any queueing techs like Kafka. +Even tho we can replace big parts of our unreliable architecture with Temporal +often it's not a complete replacement and we still have services that produce +messages/events to Kafka topics and workflow results need to be pushed to Kafka in order +to be consumed by these existing services. +In this sample we show how messages sent to Kafka topics can trigger workflow execution +as well as how via activities we can produce messages to Kafka topics that can be consumed +by other existing services you might have. + +## How to use +Enter a message you want to set to Kafka topic. Message consumer when it receives it +will start a workflow execution and deliver message to it as signal. +Workflow execution performs some sample steps. For each step it executes an activity which uses +Kafka producer to send message to Kafka topic. +In the UI we listen on this kafka topic and you will see all messages produced by activities +show up dynamically as they are happening. + +## Note +We use embedded (in-memory) Kafka to make it easier to run this sample. +You should not use this in your applications outside of tests. \ No newline at end of file diff --git a/springboot/src/main/resources/application.yaml b/springboot/src/main/resources/application.yaml index a6177bde4..e1b830bce 100644 --- a/springboot/src/main/resources/application.yaml +++ b/springboot/src/main/resources/application.yaml @@ -1,6 +1,8 @@ server: port: 3030 spring: + main: + allow-bean-definition-overriding: true application: name: temporal-samples # temporal specific configs @@ -37,6 +39,11 @@ spring: h2: console: enabled: true + ## kafka setup for samples + kafka: + consumer: + auto-offset-reset: earliest + bootstrap-servers: localhost:9092 # actuator (sdk metrics) management: endpoints: @@ -47,3 +54,8 @@ management: samples: data: language: english + message: + topic: + name: samples-topic + group: + name: samples-group diff --git a/springboot/src/main/resources/static/js/jquery.sse.js b/springboot/src/main/resources/static/js/jquery.sse.js new file mode 100644 index 000000000..67bd52ecd --- /dev/null +++ b/springboot/src/main/resources/static/js/jquery.sse.js @@ -0,0 +1,199 @@ +/* + * jQuery Plugin for Server-Sent Events (SSE) EventSource Polyfill v0.1.3 + * https://github.com/byjg/jquery-sse + * + * This document is licensed as free software under the terms of the + * MIT License: http://www.opensource.org/licenses/mit-license.php + * + * Copyright (c) 2015 by JG (JoΓ£o Gilberto MagalhΓ£es). + */ +(function ($) { + $.extend({ + SSE: function (url, customSettings) { + var sse = {instance: null, type: null}; + + var settings = { + onOpen: function (e) { + }, + onEnd: function (e) { + }, + onError: function (e) { + }, + onMessage: function (e) { + }, + options: {}, + headers: {}, + events: {} + }; + + $.extend(settings, customSettings); + + sse._url = url; + sse._settings = settings; + + // Start the proper EventSource object or Ajax fallback + sse._start = sse.start; + sse.start = function () { + if (this.instance) { + return false; + } + + if (!window.EventSource || this._settings.options.forceAjax || (Object.keys(this._settings.headers).length > 0)) { + createAjax(this); + } else { + createEventSource(this); + } + + return true; + }; + + // Stop the proper object + sse.stop = function () { + if (!this.instance) { + return false; + } + + if (!window.EventSource || this._settings.options.forceAjax || (Object.keys(this._settings.headers).length > 0)) { + // Nothing to do; + } else { + this.instance.close(); + } + this._settings.onEnd(); + + this.instance = null; + this.type = null; + + return true; + + }; + + return sse; + + } + }); + + + // Private Method for Handle EventSource object + function createEventSource(me) { + me.type = 'event'; + me.instance = new EventSource(me._url); + me.instance.successCount = 0; + + me.instance.onmessage = me._settings.onMessage; + me.instance.onopen = function (e) { + if (me.instance.successCount++ === 0) { + me._settings.onOpen(e); + } + }; + me.instance.onerror = function (e) { + if (e.target.readyState === EventSource.CLOSED) { + me._settings.onError(e); + } + }; + + for (var key in me._settings.events) { + me.instance.addEventListener(key, me._settings.events[key], false); + } + } + + // Handle the Ajax instance (fallback) + function createAjax(me) { + me.type = 'ajax'; + me.instance = {successCount: 0, id: null, retry: 3000, data: "", event: ""}; + runAjax(me); + } + + // Handle the continous Ajax request (fallback) + function runAjax(me) { + if (!me.instance) { + return; + } + + var headers = {'Last-Event-ID': me.instance.id}; + + $.extend(headers, me._settings.headers); + + $.ajax({ + url: me._url, + method: 'GET', + headers: headers, + success: function (receivedData, status, info) { + if (!me.instance) { + return; + } + + if (me.instance.successCount++ === 0) { + me._settings.onOpen(); + } + + var lines = receivedData.split("\n"); + + // Process the return to generate a compatible SSE response + me.instance.data = ""; + var countBreakLine = 0; + for (var key in lines) { + var separatorPos = lines[key].indexOf(":"); + var item = [ + lines[key].substr(0, separatorPos), + lines[key].substr(separatorPos + 1) + ]; + switch (item[0]) { + // If the first part is empty, needed to check another sequence + case "": + if (!item[1] && countBreakLine++ === 1) { // Avoid comments! + eventMessage = { + data: me.instance.data, + lastEventId: me.instance.id, + origin: 'http://' + info.getResponseHeader('Host'), + returnValue: true + }; + + // If there are a custom event then call it + if (me.instance.event && me._settings.events[me.instance.event]) { + me._settings.events[me.instance.event](eventMessage); + } else { + me._settings.onMessage(eventMessage); + } + me.instance.data = ""; + me.instance.event = ""; + countBreakLine = 0; + } + break; + + // Define the new retry object; + case "retry": + countBreakLine = 0; + me.instance.retry = parseInt(item[1].trim()); + break; + + // Define the new ID + case "id": + countBreakLine = 0; + me.instance.id = item[1].trim(); + break; + + // Define a custom event + case "event": + countBreakLine = 0; + me.instance.event = item[1].trim(); + break; + + // Define the data to be processed. + case "data": + countBreakLine = 0; + me.instance.data += (me.instance.data !== "" ? "\n" : "") + item[1].trim(); + break; + + default: + countBreakLine = 0; + } + } + setTimeout(function () { + runAjax(me); + }, me.instance.retry); + }, + error: me._settings.onError + }); + } + +})(jQuery); diff --git a/springboot/src/main/resources/static/js/samplessse.js b/springboot/src/main/resources/static/js/samplessse.js new file mode 100644 index 000000000..79dc90371 --- /dev/null +++ b/springboot/src/main/resources/static/js/samplessse.js @@ -0,0 +1,18 @@ +$( document ).ready(function() { + + var sse = $.SSE('/kafka-messages', { + onMessage: function(e){ + console.log(e); + $('#kafka-messages tr:last').after(''+e.data+''); + }, + onError: function(e){ + sse.stop(); + console.log("Could not connect..Stopping SSE"); + }, + onEnd: function(e){ + console.log("End"); + } + }); + sse.start(); + +}); \ No newline at end of file diff --git a/springboot/src/main/resources/templates/index.html b/springboot/src/main/resources/templates/index.html index 8b4ab28fe..afa8a6abe 100644 --- a/springboot/src/main/resources/templates/index.html +++ b/springboot/src/main/resources/templates/index.html @@ -16,6 +16,9 @@
Temporal Java SDK Samples
+ diff --git a/springboot/src/main/resources/templates/kafka.html b/springboot/src/main/resources/templates/kafka.html new file mode 100644 index 000000000..1ac9b9468 --- /dev/null +++ b/springboot/src/main/resources/templates/kafka.html @@ -0,0 +1,65 @@ + + + + + +
+
+
+

Temporal Java SDK Samples

+
This sample shows how we can trigger and signal workflow executions by sending messages + to Kafka topic. It also shows how workflows can send updates and result to Kafka for other + services to consume.
Enter a message in the form and submit. This will trigger a workflow + and the messages it sends to Kafka are shown on the page dynamically.
+


+
+
+

Message:

+

+

+
+
+
+
+
+
+
+
+ + + + + + +
Kafka Messages:
+
+
+
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java index d2eaf41d1..0fcf65da3 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java @@ -28,13 +28,21 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; import org.springframework.util.Assert; @SpringBootTest(classes = HelloSampleTest.Configuration.class) +@ActiveProfiles("test") @TestInstance(TestInstance.Lifecycle.PER_CLASS) +// set this to omit setting up embedded kafka +@EnableAutoConfiguration(exclude = {KafkaAutoConfiguration.class}) +@DirtiesContext public class HelloSampleTest { @Autowired ConfigurableApplicationContext applicationContext; diff --git a/springboot/src/test/java/io/temporal/samples/springboot/KafkaConsumerTestHelper.java b/springboot/src/test/java/io/temporal/samples/springboot/KafkaConsumerTestHelper.java new file mode 100644 index 000000000..418aab421 --- /dev/null +++ b/springboot/src/test/java/io/temporal/samples/springboot/KafkaConsumerTestHelper.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import java.util.concurrent.CountDownLatch; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +public class KafkaConsumerTestHelper { + private CountDownLatch latch = new CountDownLatch(5); + private String payload = null; + + @KafkaListener(id = "samples-test-id", topics = "${samples.message.topic.name}") + public void receive(ConsumerRecord consumerRecord) { + + setPayload(consumerRecord.toString()); + latch.countDown(); + } + + public CountDownLatch getLatch() { + return latch; + } + + public String getPayload() { + return payload; + } + + private void setPayload(String payload) { + this.payload = payload; + } +} diff --git a/springboot/src/test/java/io/temporal/samples/springboot/KafkaSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/KafkaSampleTest.java new file mode 100644 index 000000000..97068118e --- /dev/null +++ b/springboot/src/test/java/io/temporal/samples/springboot/KafkaSampleTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.samples.springboot.kafka.MessageWorkflow; +import io.temporal.testing.TestWorkflowEnvironment; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.util.Assert; + +@SpringBootTest(classes = KafkaSampleTest.Configuration.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@EmbeddedKafka( + partitions = 1, + bootstrapServersProperty = "spring.kafka.bootstrap-servers", + controlledShutdown = true) +@DirtiesContext +public class KafkaSampleTest { + + @Autowired ConfigurableApplicationContext applicationContext; + + @Autowired TestWorkflowEnvironment testWorkflowEnvironment; + + @Autowired WorkflowClient workflowClient; + + @Autowired KafkaConsumerTestHelper consumer; + + @BeforeEach + void setUp() { + applicationContext.start(); + } + + @Test + public void testKafkaWorflow() throws Exception { + MessageWorkflow workflow = + workflowClient.newWorkflowStub( + MessageWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("KafkaSampleTaskQueue") + .setWorkflowId("NewMessageWorkflow") + .build()); + + WorkflowClient.start(workflow::start); + workflow.update("This is a test message"); + WorkflowStub.fromTyped(workflow).getResult(Void.class); + consumer.getLatch().await(); + + Assert.isTrue(consumer.getLatch().getCount() == 0L, "Invalid latch count"); + Assert.isTrue( + consumer.getPayload().contains("Completing execution: NewMessageWorkflow"), + "Invalid last event payload"); + } + + @ComponentScan + public static class Configuration {} +} diff --git a/springboot/src/test/java/io/temporal/samples/springboot/HelloUpdateTest.java b/springboot/src/test/java/io/temporal/samples/springboot/UpdateSampleTest.java similarity index 85% rename from springboot/src/test/java/io/temporal/samples/springboot/HelloUpdateTest.java rename to springboot/src/test/java/io/temporal/samples/springboot/UpdateSampleTest.java index c71027f8e..1552631f6 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/HelloUpdateTest.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/UpdateSampleTest.java @@ -29,13 +29,21 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; -@SpringBootTest(classes = HelloUpdateTest.Configuration.class) +@SpringBootTest(classes = HelloSampleTest.Configuration.class) +@ActiveProfiles("test") @TestInstance(TestInstance.Lifecycle.PER_CLASS) -public class HelloUpdateTest { +// set this to omit setting up embedded kafka +@EnableAutoConfiguration(exclude = {KafkaAutoConfiguration.class}) +@DirtiesContext +public class UpdateSampleTest { @Autowired ConfigurableApplicationContext applicationContext; diff --git a/springboot/src/test/resources/application.yaml b/springboot/src/test/resources/application.yaml index 931aa0a86..b81a11934 100644 --- a/springboot/src/test/resources/application.yaml +++ b/springboot/src/test/resources/application.yaml @@ -1,6 +1,8 @@ server: port: 3030 spring: + main: + allow-bean-definition-overriding: true application: name: temporal-samples # temporal specific configs @@ -24,7 +26,17 @@ spring: hibernate: ddl-auto: create-drop defer-datasource-initialization: true + ## kafka setup for samples + kafka: + consumer: + auto-offset-reset: earliest + bootstrap-servers: ${spring.embedded.kafka.brokers} # specific for samples samples: data: language: english + message: + topic: + name: samples-test-topic + group: + name: samples-group From 09ce38adc57ca610474391fe404d027c3b8bf9b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jul 2023 21:09:40 -0400 Subject: [PATCH 095/240] Bump com.diffplug.spotless from 6.17.0 to 6.19.0 (#486) Bumps com.diffplug.spotless from 6.17.0 to 6.19.0. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 30336802d..6ebd4e56c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.1.0" - id 'com.diffplug.spotless' version '6.17.0' apply false + id 'com.diffplug.spotless' version '6.19.0' apply false id 'org.springframework.boot' version '2.7.13' } From 0bab4fa4f2a4010ad518e4ff6f5fe9eb83d6a364 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jul 2023 21:10:12 -0400 Subject: [PATCH 096/240] Bump io.opentelemetry:opentelemetry-bom from 1.26.0 to 1.27.0 (#485) Bumps [io.opentelemetry:opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.26.0 to 1.27.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.26.0...v1.27.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6ebd4e56c..608b00a17 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ subprojects { targetCompatibility = JavaVersion.VERSION_1_8 } ext { - otelVersion = '1.26.0' + otelVersion = '1.27.0' otelVersionAlpha = "${otelVersion}-alpha" javaSDKVersion = '1.20.0' jarVersion = '1.0.0' From 62fac2afdef8ee3abea2042e5761d53c4fbc1078 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jul 2023 21:10:43 -0400 Subject: [PATCH 097/240] Bump ch.qos.logback:logback-classic from 1.4.7 to 1.4.8 (#487) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.7 to 1.4.8. - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.7...v_1.4.8) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b01b2bfe0..60ee502a5 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.7' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.8' implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) From c7ed80cd1a5fbbc6b787d202357b56a097c1e68b Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 4 Jul 2023 15:06:46 -0400 Subject: [PATCH 098/240] Fix errorprone and compiler warnings (#496) * Fix errorprone and compiler warnings Signed-off-by: Tihomir Surdilovic * update - fail build on any issues Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 3 ++- build.gradle | 5 +++++ core/build.gradle | 6 +----- .../temporal/samples/hello/HelloActivity.java | 2 +- .../hello/HelloActivityExclusiveChoice.java | 4 ++-- .../samples/hello/HelloActivityRetry.java | 2 +- .../io/temporal/samples/hello/HelloAsync.java | 4 ++-- .../hello/HelloAsyncActivityCompletion.java | 20 +++++++++---------- .../samples/hello/HelloAsyncLambda.java | 4 ++-- .../hello/HelloDetachedCancellationScope.java | 12 +++++------ .../temporal/samples/hello/HelloDynamic.java | 16 +++++++-------- .../samples/hello/HelloException.java | 6 +++--- .../samples/hello/HelloParallelActivity.java | 2 +- .../io/temporal/samples/hello/HelloSaga.java | 12 +++++------ .../samples/hello/HelloSearchAttributes.java | 2 +- .../samples/hello/HelloSideEffect.java | 18 ++++++++--------- .../frequent/FrequentPollingWorkflowImpl.java | 2 +- .../InfrequentPollingWorkflowImpl.java | 2 +- .../java/io/temporal/samples/ssl/Starter.java | 2 +- .../samples/hello/HelloDynamicTest.java | 2 +- .../samples/springboot/SamplesController.java | 10 +++++----- .../springboot/kafka/KafkaActivityImpl.java | 8 +++++++- .../springboot/kafka/MessageController.java | 2 +- 23 files changed, 77 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index e0b6dc4fa..00148332f 100644 --- a/README.md +++ b/README.md @@ -142,4 +142,5 @@ More info on each sample: - [**Hello**](/springboot/src/main/java/io/temporal/samples/springboot/hello): Invoke simple "Hello" workflow from a GET endpoint - [**SDK Metrics**](/springboot/src/main/java/io/temporal/samples/springboot/metrics): Learn how to set up SDK Metrics - [**Synchronous Update**](/springboot/src/main/java/io/temporal/samples/springboot/update): Learn how to use Synchronous Update feature with this purchase sample - +- [**Kafka Request / Reply**](/springboot/src/main/java/io/temporal/samples/springboot/kafka): Sample showing possible integration with event streaming platforms such as Kafka + diff --git a/build.gradle b/build.gradle index 608b00a17..35f0566db 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,11 @@ subprojects { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } + + compileJava { + options.compilerArgs << "-Werror" + } + ext { otelVersion = '1.27.0' otelVersionAlpha = "${otelVersion}-alpha" diff --git a/core/build.gradle b/core/build.gradle index 60ee502a5..dd9a036a2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -46,11 +46,7 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.20.0') - } else { - errorprone('com.google.errorprone:error_prone_core:2.20.0') - } + errorprone('com.google.errorprone:error_prone_core:2.20.0') } } diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java index b8173ffba..9e46dfe63 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java @@ -150,7 +150,7 @@ public static void main(String[] args) { */ worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java index 892b419cf..0af214471 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java @@ -107,7 +107,7 @@ public interface OrderFruitsActivities { // Define the workflow implementation. It implements our orderFruit workflow method public static class PurchaseFruitsWorkflowImpl implements PurchaseFruitsWorkflow { - /** + /* * Define the OrderActivities stub. Activity stubs implements activity interfaces and proxy * calls to it to Temporal activity invocations. Since Temporal activities are reentrant, a * single activity stub can be used for multiple activity invocations. @@ -208,7 +208,7 @@ public static void main(String[] args) { */ worker.registerWorkflowImplementationTypes(PurchaseFruitsWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java index 5c6a77d0d..e7ca4a9d4 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java @@ -185,7 +185,7 @@ public static void main(String[] args) { */ worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsync.java b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java index 0b077bd94..99b1e8928 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsync.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java @@ -83,7 +83,7 @@ public interface GreetingActivities { // Define the workflow implementation which implements our getGreeting workflow method. public static class GreetingWorkflowImpl implements GreetingWorkflow { - /** + /* * Define the GreetingActivities stub. Activity stubs are proxies for activity invocations that * are executed outside of the workflow thread on the activity worker, that can be on a * different host. Temporal is going to dispatch the activity results back to the workflow and @@ -155,7 +155,7 @@ public static void main(String[] args) { */ worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java index 6a1b334f0..b2409487d 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java @@ -84,7 +84,7 @@ public interface GreetingActivities { // Define the workflow implementation which implements the getGreeting workflow method. public static class GreetingWorkflowImpl implements GreetingWorkflow { - /** + /* * Define the GreetingActivities stub. Activity stubs are proxies for activity invocations that * are executed outside of the workflow thread on the activity worker, that can be on a * different host. Temporal is going to dispatch the activity results back to the workflow and @@ -112,7 +112,7 @@ public String getGreeting(String name) { */ static class GreetingActivitiesImpl implements GreetingActivities { - /** + /* * ActivityCompletionClient is used to asynchronously complete activities. In this example we * will use this client alongside with {@link * io.temporal.activity.ActivityExecutionContext#doNotCompleteOnReturn()} which means our @@ -134,7 +134,7 @@ public String composeGreeting(String greeting, String name) { // Set a correlation token that can be used to complete the activity asynchronously byte[] taskToken = context.getTaskToken(); - /** + /* * For the example we will use a {@link java.util.concurrent.ForkJoinPool} to execute our * activity. In real-life applications this could be any service. The composeGreetingAsync * method is the one that will actually complete workflow action execution. @@ -165,37 +165,37 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc // Get a Workflow service stub. WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - /** + /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow * Executions. */ WorkflowClient client = WorkflowClient.newInstance(service); - /** + /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. */ WorkerFactory factory = WorkerFactory.newInstance(client); - /** + /* * Define the workflow worker. Workflow workers listen to a defined task queue and process * workflows and activities. */ Worker worker = factory.newWorker(TASK_QUEUE); - /** + /* * Register our Workflow Types with the Worker. Workflow Types must be known to the Worker at * runtime in order for it to poll for Workflow Tasks. */ worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ ActivityCompletionClient completionClient = client.newActivityCompletionClient(); worker.registerActivitiesImplementations(new GreetingActivitiesImpl(completionClient)); - /** + /* * Start all the Workers registered for a specific Task Queue. The Workers then start polling * for Workflow Tasks and Activity Tasks. */ @@ -210,7 +210,7 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc .setTaskQueue(TASK_QUEUE) .build()); - /** + /* * Here we use {@link io.temporal.client.WorkflowClient} to execute our workflow asynchronously. * It gives us back a {@link java.util.concurrent.CompletableFuture}. We can then call its get * method to block and wait until a result is available. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java index 14fc8cfbd..cf860d06a 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java @@ -83,7 +83,7 @@ public interface GreetingActivities { // Define the workflow implementation which implements our getGreeting workflow method. public static class GreetingWorkflowImpl implements GreetingWorkflow { - /** + /* * Define the GreetingActivities stub. Activity stubs are proxies for activity invocations that * are executed outside of the workflow thread on the activity worker, that can be on a * different host. Temporal is going to dispatch the activity results back to the workflow and @@ -173,7 +173,7 @@ public static void main(String[] args) { */ worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java index a61b446c5..45f4c7509 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java @@ -153,36 +153,36 @@ public static void main(String[] args) throws InterruptedException { // Get a Workflow service stub. WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - /** + /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow * Executions. */ WorkflowClient client = WorkflowClient.newInstance(service); - /** + /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. */ WorkerFactory factory = WorkerFactory.newInstance(client); - /** + /* * Define the workflow worker. Workflow workers listen to a defined task queue and process * workflows and activities. */ Worker worker = factory.newWorker(TASK_QUEUE); - /** + /* * Register our Workflow Types with the Worker. Workflow Types must be known to the Worker at * runtime. */ worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ worker.registerActivitiesImplementations(new GreetingActivitiesImpl()); - /** + /* * Start all the Workers that are in this process. The Workers will then start polling for * Workflow Tasks and Activity Tasks. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java index e9ba21da7..c88a79b5e 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java @@ -93,42 +93,42 @@ public static void main(String[] arg) { // Get a Workflow service stub. WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - /** + /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow * Executions. */ WorkflowClient client = WorkflowClient.newInstance(service); - /** + /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. */ WorkerFactory factory = WorkerFactory.newInstance(client); - /** + /* * Define the workflow worker. Workflow workers listen to a defined task queue and process * workflows and activities. */ Worker worker = factory.newWorker(TASK_QUEUE); - /** + /* * Register our dynamic workflow implementation with the worker. Workflow implementations must * be known to the worker at runtime in order to dispatch workflow tasks. */ worker.registerWorkflowImplementationTypes(DynamicGreetingWorkflowImpl.class); - /** + /* * Register our dynamic workflow activity implementation with the worker. Since workflow * activities are stateless and thread-safe, we need to register a shared instance. */ worker.registerActivitiesImplementations(new DynamicGreetingActivityImpl()); - /** + /* * Start all the Workers that are in this process. The Workers will then start polling for * Workflow Tasks and Activity Tasks. */ factory.start(); - /** + /* * Create the workflow stub Note that the Workflow type is not explicitly registered with the * Worker */ @@ -136,7 +136,7 @@ public static void main(String[] arg) { WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(WORKFLOW_ID).build(); WorkflowStub workflow = client.newUntypedWorkflowStub("DynamicWF", workflowOptions); - /** Start workflow execution and signal right after Pass in the workflow args and signal args */ + // Start workflow execution and signal right after Pass in the workflow args and signal args workflow.signalWithStart("greetingSignal", new Object[] {"John"}, new Object[] {"Hello"}); // Wait for workflow to finish getting the results diff --git a/core/src/main/java/io/temporal/samples/hello/HelloException.java b/core/src/main/java/io/temporal/samples/hello/HelloException.java index bf52377b7..33dd03b92 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloException.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloException.java @@ -114,7 +114,7 @@ public String getGreeting(String name) { // Define the child workflow implementation. It implements the composeGreeting workflow method public static class GreetingChildImpl implements GreetingChild { - /** + /* * Define the GreetingActivities stub. Activity stubs are proxies for activity invocations that * are executed outside of the workflow thread on the activity worker, that can be on a * different host. Temporal is going to dispatch the activity results back to the workflow and @@ -143,7 +143,7 @@ public String composeGreeting(String greeting, String name) { } } - /** + /* * Implementation of the workflow activity interface. It overwrites the defined composeGreeting * activity method. */ @@ -197,7 +197,7 @@ public static void main(String[] args) { */ worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class, GreetingChildImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java index 147f0ba97..6925cef1c 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java @@ -161,7 +161,7 @@ public static void main(String[] args) { */ worker.registerWorkflowImplementationTypes(MultiGreetingWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSaga.java b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java index 6825df681..d0180e35d 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSaga.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java @@ -72,7 +72,7 @@ public interface ChildWorkflowOperation { // Define the child workflow implementation. It implements the execute workflow method public static class ChildWorkflowOperationImpl implements ChildWorkflowOperation { - /** + /* * Define the ActivityOperation stub. Activity stubs are proxies for activity invocations that * are executed outside of the workflow thread on the activity worker, that can be on a * different host. Temporal is going to dispatch the activity results back to the workflow and @@ -116,7 +116,7 @@ public interface ChildWorkflowCompensation { // workflow method public static class ChildWorkflowCompensationImpl implements ChildWorkflowCompensation { - /** + /* * Define the ActivityOperation stub. Activity stubs are proxies for activity invocations that * are executed outside of the workflow thread on the activity worker, that can be on a * different host. Temporal is going to dispatch activity results back to the workflow and @@ -193,7 +193,7 @@ public interface SagaWorkflow { // Define the main workflow implementation. It implements the execute workflow method public static class SagaWorkflowImpl implements SagaWorkflow { - /** + /* * Define the ActivityOperation stub. Activity stubs are proxies for activity invocations that * are executed outside of the workflow thread on the activity worker, that can be on a * different host. Temporal is going to dispatch activity results back to the workflow and @@ -215,7 +215,7 @@ public void execute() { try { - /** + /* * First we show how to compensate sync child workflow invocations. We first create a child * workflow stub and execute its "execute" method. Then we create a stub of the child * compensation workflow and register it with Saga. At this point this compensation workflow @@ -228,7 +228,7 @@ public void execute() { Workflow.newChildWorkflowStub(ChildWorkflowCompensation.class); saga.addCompensation(c1::compensate, -10); - /** + /* * Now we show compensation of workflow activities which are invoked asynchronously. We * invoke the activity "execute" method async. Then we register its "compensate" method as * the compensation method for it. @@ -305,7 +305,7 @@ public static void main(String[] args) { HelloSaga.ChildWorkflowOperationImpl.class, HelloSaga.ChildWorkflowCompensationImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java index 9dfabdd07..e9d28cc01 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java @@ -158,7 +158,7 @@ public static void main(String[] args) { */ worker.registerWorkflowImplementationTypes(HelloSearchAttributes.GreetingWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java index 5d440f230..faa36f005 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java @@ -128,7 +128,7 @@ public String execute() { // Replay-safe way to create random uuid randomUUID = Workflow.randomUUID(); - /** + /* * Random number using side effects. Note that this value is recorded in workflow history. On * replay the same value is returned so determinism is guaranteed. */ @@ -140,7 +140,7 @@ public String execute() { return random.nextInt(); }); - /** + /* * Since our randoms are all created safely (using SideEffects or Workflow deterministic * methods) the workflow result should be same as the queries ran after workflow completion. * In the case we did not use safe methods, the queries could have a different result. @@ -181,36 +181,36 @@ public static void main(String[] args) { // Define the workflow service. WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - /** + /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow * Executions. */ WorkflowClient client = WorkflowClient.newInstance(service); - /** + /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. */ WorkerFactory factory = WorkerFactory.newInstance(client); - /** + /* * Define the workflow worker. Workflow workers listen to a defined task queue and process * workflows and activities. */ Worker worker = factory.newWorker(TASK_QUEUE); - /** + /* * Register our workflow implementation with the worker. Workflow implementations must be known * to the worker at runtime in order to dispatch workflow tasks. */ worker.registerWorkflowImplementationTypes(SideEffectWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ worker.registerActivitiesImplementations(new SideEffectActivitiesImpl()); - /** + /* * Start all the workers registered for a specific task queue. The started workers then start * polling for workflows and activities. */ @@ -225,7 +225,7 @@ public static void main(String[] args) { .setTaskQueue(TASK_QUEUE) .build()); - /** + /* * Execute our workflow and wait for it to complete. The call to our start method is * synchronous. * diff --git a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java index b4d8cfe70..b50f538c3 100644 --- a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java @@ -28,7 +28,7 @@ public class FrequentPollingWorkflowImpl implements PollingWorkflow { @Override public String exec() { - /** + /* * Frequent polling (1 second or faster) should be done inside the activity itself. Note that * the activity has to heart beat on each iteration. Note that we need to set our * HeartbeatTimeout in ActivityOptions shorter than the StartToClose timeout. You can use an diff --git a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java index 43f096e40..7d1854558 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java @@ -29,7 +29,7 @@ public class InfrequentPollingWorkflowImpl implements PollingWorkflow { @Override public String exec() { - /** + /* * Infrequent polling via activity can be implemented via activity retries. For this sample we * want to poll the test service every 60 seconds. Here we: * diff --git a/core/src/main/java/io/temporal/samples/ssl/Starter.java b/core/src/main/java/io/temporal/samples/ssl/Starter.java index 9b8c6170d..b61b3b761 100644 --- a/core/src/main/java/io/temporal/samples/ssl/Starter.java +++ b/core/src/main/java/io/temporal/samples/ssl/Starter.java @@ -81,7 +81,7 @@ public static void main(String[] args) throws Exception { */ worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); - /** + /* * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, * the Activity Type is a shared instance. */ diff --git a/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java b/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java index 4c3e09e2f..96e3513b9 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java @@ -49,7 +49,7 @@ public void testActivityImpl() { WorkflowStub workflow = testWorkflowRule.getWorkflowClient().newUntypedWorkflowStub("DynamicWF", workflowOptions); - /** Start workflow execution and signal right after Pass in the workflow args and signal args */ + // Start workflow execution and signal right after Pass in the workflow args and signal args workflow.signalWithStart("greetingSignal", new Object[] {"John"}, new Object[] {"Hello"}); // Wait for workflow to finish getting the results diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index 006049096..bf5f86767 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -65,7 +65,7 @@ ResponseEntity helloSample(@RequestBody Person person) { .build()); // bypass thymeleaf, don't return template name just result - return new ResponseEntity("\"" + workflow.sayHello(person) + "\"", HttpStatus.OK); + return new ResponseEntity<>("\"" + workflow.sayHello(person) + "\"", HttpStatus.OK); } @GetMapping("/metrics") @@ -108,9 +108,9 @@ ResponseEntity purchase(@RequestBody Purchase purchase) { workflow.exit(); WorkflowStub.fromTyped(workflow).getResult(Void.class); if (!isValidPurchase) { - return new ResponseEntity("\"Invalid purchase\"", HttpStatus.NOT_FOUND); + return new ResponseEntity<>("\"Invalid purchase\"", HttpStatus.NOT_FOUND); } - return new ResponseEntity("\"" + "Purchase successful" + "\"", HttpStatus.OK); + return new ResponseEntity<>("\"" + "Purchase successful" + "\"", HttpStatus.OK); } catch (WorkflowUpdateException | StatusRuntimeException e) { // for sample send exit to workflow exec and wait till it completes workflow.exit(); @@ -121,7 +121,7 @@ ResponseEntity purchase(@RequestBody Purchase purchase) { message = e.getCause().getMessage(); } - return new ResponseEntity("\"" + message + "\"", HttpStatus.NOT_FOUND); + return new ResponseEntity<>("\"" + message + "\"", HttpStatus.NOT_FOUND); } } @@ -150,6 +150,6 @@ ResponseEntity sendToKafka(@RequestBody String message) { // wait till exec completes WorkflowStub.fromTyped(workflow).getResult(Void.class); // bypass thymeleaf, don't return template name just result - return new ResponseEntity("\" Message workflow completed\"", HttpStatus.OK); + return new ResponseEntity<>("\" Message workflow completed\"", HttpStatus.OK); } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java index 8b9b4c781..81bb6634f 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java @@ -19,6 +19,7 @@ package io.temporal.samples.springboot.kafka; +import io.temporal.failure.ApplicationFailure; import io.temporal.spring.boot.ActivityImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -39,6 +40,11 @@ public class KafkaActivityImpl implements KafkaActivity { @Override public void sendMessage(String message) { - kafkaTemplate.send(topicName, message); + try { + kafkaTemplate.send(topicName, message).get(); + } catch (Exception e) { + throw ApplicationFailure.newFailure( + "Unable to send message.", e.getClass().getName(), e.getMessage()); + } } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java index 8ba518fee..6b84ebd21 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java @@ -47,6 +47,6 @@ public List getEmitters() { } public SseEmitter getLatestEmitter() { - return (emitters.isEmpty()) ? null : emitters.get(emitters.size() - 1); + return emitters.isEmpty() ? null : emitters.get(emitters.size() - 1); } } From 664cd5fa5039967da99a9ed4c3f231ac935b789b Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Mon, 10 Jul 2023 16:24:54 -0400 Subject: [PATCH 099/240] SpringBoot Sample - customize options (#497) * SpringBoot Sample - optimize options Signed-off-by: Tihomir Surdilovic * update text Signed-off-by: Tihomir Surdilovic * updated readme Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 3 +- .../samples/springboot/SamplesController.java | 24 +++++ .../customize/CustomizeActivity.java | 27 +++++ .../customize/CustomizeActivityImpl.java | 32 ++++++ .../customize/CustomizeWorkflow.java | 29 +++++ .../customize/CustomizeWorkflowImpl.java | 66 ++++++++++++ .../samples/springboot/customize/README.md | 26 +++++ .../customize/TemporalOptionsConfig.java | 101 ++++++++++++++++++ .../main/resources/templates/customize.html | 59 ++++++++++ .../src/main/resources/templates/index.html | 3 + .../springboot/CustomizeSampleTest.java | 73 +++++++++++++ 11 files changed, 442 insertions(+), 1 deletion(-) create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivity.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivityImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflow.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflowImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/customize/README.md create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java create mode 100644 springboot/src/main/resources/templates/customize.html create mode 100644 springboot/src/test/java/io/temporal/samples/springboot/CustomizeSampleTest.java diff --git a/README.md b/README.md index 00148332f..766ee621f 100644 --- a/README.md +++ b/README.md @@ -143,4 +143,5 @@ More info on each sample: - [**SDK Metrics**](/springboot/src/main/java/io/temporal/samples/springboot/metrics): Learn how to set up SDK Metrics - [**Synchronous Update**](/springboot/src/main/java/io/temporal/samples/springboot/update): Learn how to use Synchronous Update feature with this purchase sample - [**Kafka Request / Reply**](/springboot/src/main/java/io/temporal/samples/springboot/kafka): Sample showing possible integration with event streaming platforms such as Kafka - +- [**Customize Options**](/springboot/src/main/java/io/temporal/samples/springboot/customize): Sample showing how to customize options such as WorkerOptions, WorkerFactoryOptions, etc (see options config [here](springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java)) + diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index bf5f86767..6d8540704 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -24,6 +24,7 @@ import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.client.WorkflowUpdateException; +import io.temporal.samples.springboot.customize.CustomizeWorkflow; import io.temporal.samples.springboot.hello.HelloWorkflow; import io.temporal.samples.springboot.hello.model.Person; import io.temporal.samples.springboot.kafka.MessageWorkflow; @@ -152,4 +153,27 @@ ResponseEntity sendToKafka(@RequestBody String message) { // bypass thymeleaf, don't return template name just result return new ResponseEntity<>("\" Message workflow completed\"", HttpStatus.OK); } + + @GetMapping("/customize") + public String customize(Model model) { + model.addAttribute("sample", "Customizing Options"); + return "customize"; + } + + @PostMapping( + value = "/customize", + consumes = {MediaType.APPLICATION_JSON_VALUE}, + produces = {MediaType.TEXT_HTML_VALUE}) + ResponseEntity customizeSample() { + CustomizeWorkflow workflow = + client.newWorkflowStub( + CustomizeWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("CustomizeTaskQueue") + .setWorkflowId("CustomizeSample") + .build()); + + // bypass thymeleaf, don't return template name just result + return new ResponseEntity<>("\"" + workflow.execute() + "\"", HttpStatus.OK); + } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivity.java new file mode 100644 index 000000000..06f9d03aa --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivity.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.customize; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface CustomizeActivity { + String run(String input); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivityImpl.java new file mode 100644 index 000000000..9d28c8ed9 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivityImpl.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.customize; + +import io.temporal.spring.boot.ActivityImpl; +import org.springframework.stereotype.Component; + +@Component +@ActivityImpl(taskQueues = "CustomizeTaskQueue") +public class CustomizeActivityImpl implements CustomizeActivity { + @Override + public String run(String input) { + return "Completed as " + input + " activity!"; + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflow.java new file mode 100644 index 000000000..ffe9574eb --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflow.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.customize; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface CustomizeWorkflow { + @WorkflowMethod + String execute(); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflowImpl.java new file mode 100644 index 000000000..d5b845740 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflowImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.customize; + +import io.temporal.activity.ActivityOptions; +import io.temporal.activity.LocalActivityOptions; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.TimeoutFailure; +import io.temporal.spring.boot.WorkflowImpl; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import org.slf4j.Logger; + +/** + * In our custom config we have set that worker polling on CustomizeTaskQueue to be a "local + * activity worker", meaning it would not poll for activity tasks. For this sample we will try to + * start an activity as "normal" activity which should time out, then invoke it again as local which + * should be successful. + * + * @see io.temporal.samples.springboot.customize.TemporalOptionsConfig + */ +@WorkflowImpl(taskQueues = "CustomizeTaskQueue") +public class CustomizeWorkflowImpl implements CustomizeWorkflow { + private CustomizeActivity asNormalActivity = + Workflow.newActivityStub( + CustomizeActivity.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(2)) + .setScheduleToCloseTimeout(Duration.ofSeconds(4)) + .build()); + + private CustomizeActivity asLocalActivity = + Workflow.newLocalActivityStub( + CustomizeActivity.class, + LocalActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + private Logger logger = Workflow.getLogger(CustomizeActivity.class.getName()); + + @Override + public String execute() { + try { + return asNormalActivity.run("Normal"); + } catch (ActivityFailure e) { + // We should have TimeoutFailure as activity failure cause with StartToClose timeout type + TimeoutFailure tf = (TimeoutFailure) e.getCause(); + logger.warn("asNormalActivity failed with timeout type: " + tf.getTimeoutType()); + } + return asLocalActivity.run("Local"); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/README.md b/springboot/src/main/java/io/temporal/samples/springboot/customize/README.md new file mode 100644 index 000000000..c3d412104 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/README.md @@ -0,0 +1,26 @@ +# SpringBoot Customize Options Sample + +This sample shows how to optimize default options such as +* WorkflowServiceStubsOptions +* WorkflowClientOption +* WorkerFactoryOptions +* WorkerOptions + +WorkerOptions can be optimized per worker/task queue. + +For this sample we set our specific worker to be "local activity worker" via custom options meaning +it would not poll for activity tasks. Click on "Run Workflow" button to start instance of +our sample workflow. This workflow will try to invoke our activity as "normal" +activity which should time out on ScheduleToClose timeout, then we invoke this activity +as local activity which should succeed. + +## How to run +1. Start SpringBoot from main samples repo directory: + + ./gradlew bootRun + +2. In your browser navigate to: + + http://localhost:3030/customize + +3. Press the "Run Workflow" button to start execution. You will see result show on page in 4 seconds \ No newline at end of file diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java new file mode 100644 index 000000000..cfe046707 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.customize; + +import io.temporal.client.WorkflowClientOptions; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.spring.boot.TemporalOptionsCustomizer; +import io.temporal.spring.boot.WorkerOptionsCustomizer; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.worker.WorkerOptions; +import javax.annotation.Nonnull; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TemporalOptionsConfig { + + // Worker specific options customization + @Bean + public WorkerOptionsCustomizer customWorkerOptions() { + return new WorkerOptionsCustomizer() { + @Nonnull + @Override + public WorkerOptions.Builder customize( + @Nonnull WorkerOptions.Builder optionsBuilder, + @Nonnull String workerName, + @Nonnull String taskQueue) { + + // For CustomizeTaskQueue (also name of worker) we set worker + // to only handle workflow tasks and local activities + if (taskQueue.equals("CustomizeTaskQueue")) { + optionsBuilder.setLocalActivityWorkerOnly(true); + } + return optionsBuilder; + } + }; + } + + // WorkflowServiceStubsOptions customization + @Bean + public TemporalOptionsCustomizer + customServiceStubsOptions() { + return new TemporalOptionsCustomizer() { + @Nonnull + @Override + public WorkflowServiceStubsOptions.Builder customize( + @Nonnull WorkflowServiceStubsOptions.Builder optionsBuilder) { + // set options on optionsBuilder as needed + // ... + return optionsBuilder; + } + }; + } + + // WorkflowClientOption customization + @Bean + public TemporalOptionsCustomizer customClientOptions() { + return new TemporalOptionsCustomizer() { + @Nonnull + @Override + public WorkflowClientOptions.Builder customize( + @Nonnull WorkflowClientOptions.Builder optionsBuilder) { + // set options on optionsBuilder as needed + // ... + return optionsBuilder; + } + }; + } + + // WorkerFactoryOptions customization + @Bean + public TemporalOptionsCustomizer customWorkerFactoryOptions() { + return new TemporalOptionsCustomizer() { + @Nonnull + @Override + public WorkerFactoryOptions.Builder customize( + @Nonnull WorkerFactoryOptions.Builder optionsBuilder) { + // set options on optionsBuilder as needed + // ... + return optionsBuilder; + } + }; + } +} diff --git a/springboot/src/main/resources/templates/customize.html b/springboot/src/main/resources/templates/customize.html new file mode 100644 index 000000000..ca38257f7 --- /dev/null +++ b/springboot/src/main/resources/templates/customize.html @@ -0,0 +1,59 @@ + + + + +
+
+
+

Temporal Java SDK Samples

+
This sample shows how to optimize default options such as +
    +
  • WorkflowServiceStubsOptions
  • +
  • WorkflowClientOption
  • +
  • WorkerFactoryOptions
  • +
  • WorkerOptions
  • +
+
WorkerOptions can be optimized per worker/task queue. + For this sample we set our specific worker to be "local activity worker" via custom options meaning + it would not poll for activity tasks. Click on "Run Workflow" button to start instance of + our sample workflow. This workflow will try to invoke activity as "normal" activity which should + timeout on the set ScheduleToClose timeout, we handle this activity failure + and then invoke this activity as local activity which should succeed and update the + workflow execution result on the page. +
+
+


+
+

+

+
+
+
+
+
Workflow result:
+
+
+
+
+
+ +
+ + \ No newline at end of file diff --git a/springboot/src/main/resources/templates/index.html b/springboot/src/main/resources/templates/index.html index afa8a6abe..6d0748021 100644 --- a/springboot/src/main/resources/templates/index.html +++ b/springboot/src/main/resources/templates/index.html @@ -19,6 +19,9 @@
Temporal Java SDK Samples
+ diff --git a/springboot/src/test/java/io/temporal/samples/springboot/CustomizeSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/CustomizeSampleTest.java new file mode 100644 index 000000000..5e9d82f52 --- /dev/null +++ b/springboot/src/test/java/io/temporal/samples/springboot/CustomizeSampleTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.springboot.customize.CustomizeWorkflow; +import io.temporal.testing.TestWorkflowEnvironment; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.util.Assert; + +@SpringBootTest(classes = CustomizeSampleTest.Configuration.class) +@ActiveProfiles("test") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +// set this to omit setting up embedded kafka +@EnableAutoConfiguration(exclude = {KafkaAutoConfiguration.class}) +@DirtiesContext +public class CustomizeSampleTest { + @Autowired ConfigurableApplicationContext applicationContext; + + @Autowired TestWorkflowEnvironment testWorkflowEnvironment; + + @Autowired WorkflowClient workflowClient; + + @BeforeEach + void setUp() { + applicationContext.start(); + } + + @Test + public void testHello() { + CustomizeWorkflow workflow = + workflowClient.newWorkflowStub( + CustomizeWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("CustomizeTaskQueue") + .setWorkflowId("CustomizeSampleTest") + .build()); + String result = workflow.execute(); + Assert.notNull(result, "Result should not be null"); + Assert.isTrue(result.equals("Completed as Local activity!"), "Invalid result"); + } + + @ComponentScan + public static class Configuration {} +} From 5a440805e4690dfb90c12e866dbba03692cb8e19 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Fri, 14 Jul 2023 02:10:41 -0700 Subject: [PATCH 100/240] Update Java SDK 1.20.1 (#503) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 35f0566db..879f8b4ad 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ subprojects { ext { otelVersion = '1.27.0' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.20.0' + javaSDKVersion = '1.20.1' jarVersion = '1.0.0' } From f107c79e29453ecd43dce522dfd1c980439b3762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Wed, 19 Jul 2023 00:58:52 +0200 Subject: [PATCH 101/240] add config to run spring boot samples connecting to Temporal Cloud (#505) * add config to connect to temporal cloud * add config to connect to temporal cloud --- README.md | 13 ++++++++++++- springboot/src/main/resources/application-tc.yaml | 9 +++++++++ springboot/src/main/resources/application.yaml | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 springboot/src/main/resources/application-tc.yaml diff --git a/README.md b/README.md index 766ee621f..b5a82bdd4 100644 --- a/README.md +++ b/README.md @@ -144,4 +144,15 @@ More info on each sample: - [**Synchronous Update**](/springboot/src/main/java/io/temporal/samples/springboot/update): Learn how to use Synchronous Update feature with this purchase sample - [**Kafka Request / Reply**](/springboot/src/main/java/io/temporal/samples/springboot/kafka): Sample showing possible integration with event streaming platforms such as Kafka - [**Customize Options**](/springboot/src/main/java/io/temporal/samples/springboot/customize): Sample showing how to customize options such as WorkerOptions, WorkerFactoryOptions, etc (see options config [here](springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java)) - + + +#### Temporal Cloud +To run any of the SpringBoot samples in your Temporal Cloud namespace: + +1. Edit the [application-tc.yaml](/springboot/src/main/resources/application-tc.yaml) to set your namespace and client certificates. + +2. Start SpringBoot from main repo dir with the `tc` profile: + + ./gradlew bootRun --args='--spring.profiles.active=tc' + +3. Follow the previous section from step 2 diff --git a/springboot/src/main/resources/application-tc.yaml b/springboot/src/main/resources/application-tc.yaml new file mode 100644 index 000000000..041d67e06 --- /dev/null +++ b/springboot/src/main/resources/application-tc.yaml @@ -0,0 +1,9 @@ +spring.temporal: + namespace: # https://docs.temporal.io/cloud/#temporal-cloud-namespace-id + connection: + target: .tmprl.cloud:7233 + mtls: + key-file: /path/to/key.key + cert-chain-file: /path/to/cert.pem + +# more configuration options https://github.com/temporalio/sdk-java/tree/master/temporal-spring-boot-autoconfigure-alpha#mtls \ No newline at end of file diff --git a/springboot/src/main/resources/application.yaml b/springboot/src/main/resources/application.yaml index e1b830bce..7722f9762 100644 --- a/springboot/src/main/resources/application.yaml +++ b/springboot/src/main/resources/application.yaml @@ -7,9 +7,9 @@ spring: name: temporal-samples # temporal specific configs temporal: + namespace: default connection: target: 127.0.0.1:7233 - target.namespace: default # (Note following configuration are not set by default but serve more as reference) # workers: # - task-queue: DemoTaskQueue From 47ced6dccef800462fb43c57ab094552164086bd Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 2 Aug 2023 06:50:31 -0700 Subject: [PATCH 102/240] Update SDK to v1.21.0 (#506) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 879f8b4ad..dac0c6e75 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ subprojects { ext { otelVersion = '1.27.0' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.20.1' + javaSDKVersion = '1.21.0' jarVersion = '1.0.0' } From 1ddbb391bcb53516ab3868c9508473531c60e0fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:54:28 +0200 Subject: [PATCH 103/240] Bump io.opentelemetry:opentelemetry-bom from 1.27.0 to 1.29.0 (#513) Bumps [io.opentelemetry:opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.27.0 to 1.29.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.27.0...v1.29.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index dac0c6e75..f7b66a5bc 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ subprojects { } ext { - otelVersion = '1.27.0' + otelVersion = '1.29.0' otelVersionAlpha = "${otelVersion}-alpha" javaSDKVersion = '1.21.0' jarVersion = '1.0.0' From 3b78993e4184f7e010e25ba054deb4fcccec1572 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 16 Aug 2023 13:41:19 -0600 Subject: [PATCH 104/240] Update Java SDK 1.21.1 (#514) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f7b66a5bc..1aad74e45 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ subprojects { ext { otelVersion = '1.29.0' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.21.0' + javaSDKVersion = '1.21.1' jarVersion = '1.0.0' } From 3ab932c47235278da5bd00874a2a964f7ae20106 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 28 Aug 2023 07:03:18 -0700 Subject: [PATCH 105/240] Add sample for typed search attributes (#516) --- .../hello/HelloTypedSearchAttributes.java | 223 ++++++++++++++++++ .../java/io/temporal/samples/hello/README.md | 1 + 2 files changed, 224 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java diff --git a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java new file mode 100644 index 000000000..589778c19 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; +import io.temporal.activity.ActivityOptions; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.SearchAttributeKey; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.time.Duration; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +/** + * Sample Temporal workflow that demonstrates setting up, updating, and retrieving workflow search + * attributes using the typed search attributes API. + */ +public class HelloTypedSearchAttributes { + + // Define the task queue name + static final String TASK_QUEUE = "HelloTypedSearchAttributesTaskQueue"; + + // Define our workflow unique id + static final String WORKFLOW_ID = "HelloTypedSearchAttributesWorkflow"; + + // Define all our search attributes with appropriate types + static final SearchAttributeKey CUSTOM_KEYWORD_SA = + SearchAttributeKey.forKeyword("CustomKeywordField"); + static final SearchAttributeKey CUSTOM_LONG_SA = + SearchAttributeKey.forLong("CustomIntField"); + static final SearchAttributeKey CUSTOM_DOUBLE_SA = + SearchAttributeKey.forDouble("CustomDoubleField"); + static final SearchAttributeKey CUSTOM_BOOL_SA = + SearchAttributeKey.forBoolean("CustomBoolField"); + static final SearchAttributeKey CUSTOM_OFFSET_DATE_TIME_SA = + SearchAttributeKey.forOffsetDateTime("CustomDatetimeField"); + static final SearchAttributeKey CUSTOM_STRING_SA = + SearchAttributeKey.forText("CustomStringField"); + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see WorkflowInterface + * @see WorkflowMethod + */ + @WorkflowInterface + public interface GreetingWorkflow { + + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + String getGreeting(String name); + } + + /** + * This is the Activity Definition's Interface. Activities are building blocks of any Temporal + * Workflow and contain any business logic that could perform long running computation, network + * calls, etc. + * + *

Annotating Activity Definition methods with @ActivityMethod is optional. + * + * @see ActivityInterface + * @see ActivityMethod + */ + @ActivityInterface + public interface GreetingActivities { + @ActivityMethod + String composeGreeting(String greeting, String name); + } + + // Define the workflow implementation which implements our getGreeting workflow method. + public static class GreetingWorkflowImpl implements GreetingWorkflow { + + /** + * Define the GreetingActivities stub. Activity stubs implement activity interfaces and proxy + * calls to it to Temporal activity invocations. Since Temporal activities are reentrant, a + * single activity stub can be used for multiple activity invocations. + * + *

In the {@link ActivityOptions} definition the "setStartToCloseTimeout" option sets the + * maximum time of a single Activity execution attempt. For this example it is set to 2 seconds. + */ + private final GreetingActivities activities = + Workflow.newActivityStub( + GreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String getGreeting(String name) { + // Show how to update typed search attributes inside a workflow. The first parameter shows how + // to remove a search attribute. The second parameter shows how to update a value. + Workflow.upsertTypedSearchAttributes( + CUSTOM_LONG_SA.valueUnset(), CUSTOM_KEYWORD_SA.valueSet("Hello")); + // Get the search attributes currently set on this workflow + io.temporal.common.SearchAttributes searchAttributes = Workflow.getTypedSearchAttributes(); + // Get a particular value out of the container using the typed key + String greeting = searchAttributes.get(CUSTOM_KEYWORD_SA); + // This is a blocking call that returns only after the activity has completed. + return activities.composeGreeting(greeting, name); + } + } + + /** + * Implementation of our workflow activity interface. It overwrites our defined composeGreeting + * activity method. + */ + static class GreetingActivitiesImpl implements GreetingActivities { + @Override + public String composeGreeting(String greeting, String name) { + return greeting + " " + name + "!"; + } + } + + /** + * With our Workflow and Activities defined, we can now start execution. The main method starts + * the worker and then the workflow. + */ + public static void main(String[] args) { + + // Define the workflow service. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register our workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes( + HelloTypedSearchAttributes.GreetingWorkflowImpl.class); + + /* + * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, + * the Activity Type is a shared instance. + */ + worker.registerActivitiesImplementations( + new HelloTypedSearchAttributes.GreetingActivitiesImpl()); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + // Set our workflow options. + // Note that we set our search attributes here + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .setTypedSearchAttributes(generateTypedSearchAttributes()) + .build(); + + // Create the workflow client stub. It is used to start our workflow execution. + HelloTypedSearchAttributes.GreetingWorkflow workflow = + client.newWorkflowStub(HelloTypedSearchAttributes.GreetingWorkflow.class, workflowOptions); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.getGreeting("TypedSearchAttributes"); + + // Print the workflow execution results + System.out.println(greeting); + System.exit(0); + } + + // Generate our example search option + private static io.temporal.common.SearchAttributes generateTypedSearchAttributes() { + return io.temporal.common.SearchAttributes.newBuilder() + .set(CUSTOM_KEYWORD_SA, "keyword") + .set(CUSTOM_LONG_SA, 1l) + .set(CUSTOM_DOUBLE_SA, 0.1) + .set(CUSTOM_BOOL_SA, true) + .set(CUSTOM_OFFSET_DATE_TIME_SA, OffsetDateTime.now(ZoneOffset.UTC)) + .set( + CUSTOM_STRING_SA, + "String field is for text. When query, it will be tokenized for partial match. StringTypeField cannot be used in Order By") + .build(); + } +} diff --git a/core/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md index 925862c19..09a083a7d 100644 --- a/core/src/main/java/io/temporal/samples/hello/README.md +++ b/core/src/main/java/io/temporal/samples/hello/README.md @@ -28,6 +28,7 @@ To run each hello world sample, use one of the following commands: ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSchedules ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignal ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSearchAttributes +./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloTypedSearchAttributes ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSideEffect ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloUpdate ``` From 52733da42815df02d52ed93233fd4f12fc831c27 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Fri, 15 Sep 2023 23:00:40 -0400 Subject: [PATCH 106/240] fix for child mock test (#511) Signed-off-by: Tihomir Surdilovic --- .../samples/hello/HelloChildJUnit5Test.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java index 61914a87e..7330120e5 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java @@ -24,13 +24,13 @@ import io.temporal.testing.TestWorkflowEnvironment; import io.temporal.testing.TestWorkflowExtension; import io.temporal.worker.Worker; -import java.util.concurrent.atomic.AtomicReference; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; /** Unit test for {@link HelloChild}. Doesn't use an external Temporal service. */ public class HelloChildJUnit5Test { + private HelloChild.GreetingChild child = mock(HelloChild.GreetingChildImpl.class); @RegisterExtension public static final TestWorkflowExtension testWorkflowExtension = @@ -40,28 +40,20 @@ public class HelloChildJUnit5Test { .build(); @Test - public void testMockedChild( + public void testChild( TestWorkflowEnvironment testEnv, Worker worker, HelloChild.GreetingWorkflow workflow) { - - // As new mock is created on each workflow task the only last one is useful to verify calls. - AtomicReference lastChildMock = new AtomicReference<>(); - // Factory is called to create a new workflow object on each workflow task. - worker.addWorkflowImplementationFactory( + worker.registerWorkflowImplementationFactory( HelloChild.GreetingChild.class, () -> { - HelloChild.GreetingChild child = mock(HelloChild.GreetingChild.class); - when(child.composeGreeting("Hello", "World")).thenReturn("Bye World!"); - lastChildMock.set(child); + when(child.composeGreeting(anyString(), anyString())).thenReturn("Bye World!"); return child; }); - testEnv.start(); // Execute a workflow waiting for it to complete. String greeting = workflow.getGreeting("World"); Assert.assertEquals("Bye World!", greeting); - HelloChild.GreetingChild mock = lastChildMock.get(); - verify(mock).composeGreeting(eq("Hello"), eq("World")); + verify(child).composeGreeting(eq("Hello"), eq("World")); testEnv.shutdown(); } From 27fcf36aa8a6bbfe28394f8bd1bcf73f5031d9be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 23:01:16 -0400 Subject: [PATCH 107/240] Bump io.serverlessworkflow:serverlessworkflow-util (#498) Bumps io.serverlessworkflow:serverlessworkflow-util from 4.0.3.Final to 4.0.4.Final. --- updated-dependencies: - dependency-name: io.serverlessworkflow:serverlessworkflow-util dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index dd9a036a2..f669f4de2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -30,7 +30,7 @@ dependencies { implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.3.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.4.Final' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' // we don't update it to 2.1.0 because 2.1.0 requires Java 11 From 5b6eb4d6122a65faf50b6c8d526f6046d80f8e47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 03:08:19 +0000 Subject: [PATCH 108/240] Bump io.serverlessworkflow:serverlessworkflow-spi (#500) Bumps [io.serverlessworkflow:serverlessworkflow-spi](https://github.com/serverlessworkflow/sdk-java) from 4.0.3.Final to 4.0.4.Final. - [Release notes](https://github.com/serverlessworkflow/sdk-java/releases) - [Commits](https://github.com/serverlessworkflow/sdk-java/compare/4.0.3.Final...4.0.4.Final) --- updated-dependencies: - dependency-name: io.serverlessworkflow:serverlessworkflow-spi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index f669f4de2..8a24827bb 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -29,7 +29,7 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.3.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.4.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.4.Final' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' From 446ebea834d335c34cc1888fc234c0aacd12ca02 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 23:15:15 -0400 Subject: [PATCH 109/240] Bump io.serverlessworkflow:serverlessworkflow-api (#502) Bumps [io.serverlessworkflow:serverlessworkflow-api](https://github.com/serverlessworkflow/sdk-java) from 4.0.3.Final to 4.0.4.Final. - [Release notes](https://github.com/serverlessworkflow/sdk-java/releases) - [Commits](https://github.com/serverlessworkflow/sdk-java/compare/4.0.3.Final...4.0.4.Final) --- updated-dependencies: - dependency-name: io.serverlessworkflow:serverlessworkflow-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 8a24827bb..b60fc8a6e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -27,7 +27,7 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.3.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.4.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.4.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.4.Final' From 4c6e85fdde3b24c824f222836126d2a9454e591a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 23:21:31 -0400 Subject: [PATCH 110/240] Bump io.serverlessworkflow:serverlessworkflow-validation (#501) Bumps [io.serverlessworkflow:serverlessworkflow-validation](https://github.com/serverlessworkflow/sdk-java) from 4.0.3.Final to 4.0.4.Final. - [Release notes](https://github.com/serverlessworkflow/sdk-java/releases) - [Commits](https://github.com/serverlessworkflow/sdk-java/compare/4.0.3.Final...4.0.4.Final) --- updated-dependencies: - dependency-name: io.serverlessworkflow:serverlessworkflow-validation dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b60fc8a6e..a1d3bbcf3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.4.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.3.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.4.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.4.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.4.Final' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' From 857ec701a05be39498c8c7a42e25cf30ce392293 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 23:22:26 -0400 Subject: [PATCH 111/240] Bump actions/checkout from 3 to 4 (#518) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gradle-wrapper-validation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 44e0dc102..a8195158c 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -6,5 +6,5 @@ jobs: name: "Gradle wrapper validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: gradle/wrapper-validation-action@v1 From 64e07129d4146056ba12fa4db5d5b97340af6465 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 23:23:22 -0400 Subject: [PATCH 112/240] Bump com.diffplug.spotless from 6.19.0 to 6.21.0 (#517) Bumps com.diffplug.spotless from 6.19.0 to 6.21.0. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1aad74e45..3a05cb222 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.1.0" - id 'com.diffplug.spotless' version '6.19.0' apply false + id 'com.diffplug.spotless' version '6.21.0' apply false id 'org.springframework.boot' version '2.7.13' } From 58d79eb39ef89194dbc739a305e418cd0b90bbcb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:56:55 -0400 Subject: [PATCH 113/240] Bump io.opentelemetry:opentelemetry-bom from 1.29.0 to 1.30.1 (#521) Bumps [io.opentelemetry:opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java) from 1.29.0 to 1.30.1. - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.29.0...v1.30.1) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3a05cb222..935272568 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ subprojects { } ext { - otelVersion = '1.29.0' + otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" javaSDKVersion = '1.21.1' jarVersion = '1.0.0' From c709bdaa745fa54e33c5cfd361ed55de03f8837b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:57:19 -0400 Subject: [PATCH 114/240] Bump ch.qos.logback:logback-classic from 1.4.8 to 1.4.11 (#522) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.8 to 1.4.11. - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.8...v_1.4.11) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index a1d3bbcf3..e441ca5f5 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.8' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.11' implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) From 1178878bbf83419b7725ebd923169eede3d33487 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:57:41 -0400 Subject: [PATCH 115/240] Bump org.mockito:mockito-core from 5.3.1 to 5.5.0 (#523) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.3.1 to 5.5.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.3.1...v5.5.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index e441ca5f5..12440f7cd 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation 'com.codingrodent:jackson-json-crypto:1.1.0' testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.3.1" + testImplementation "org.mockito:mockito-core:5.5.0" testImplementation(platform("org.junit:junit-bom:5.9.3")) testImplementation "org.junit.jupiter:junit-jupiter-api" From 010b700a954bb499fa114556861edba66c6e4ba1 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 26 Sep 2023 11:58:22 -0400 Subject: [PATCH 116/240] update errorprone to 2.22.0 (#528) Signed-off-by: Tihomir Surdilovic --- core/build.gradle | 2 +- .../batch/heartbeatingactivity/RecordProcessorImpl.java | 1 - springboot/build.gradle | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 12440f7cd..209477ddf 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -46,7 +46,7 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.20.0') + errorprone('com.google.errorprone:error_prone_core:2.22.0') } } diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java index 91916b30e..5d534fffa 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java @@ -36,6 +36,5 @@ public void processRecord(SingleRecord record) { } catch (InterruptedException ignored) { return; } - return; } } diff --git a/springboot/build.gradle b/springboot/build.gradle index 4adb212c5..78eccd063 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -15,9 +15,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.20.0') + errorprone('com.google.errorprone:error_prone_core:2.22.0') } else { - errorprone('com.google.errorprone:error_prone_core:2.20.0') + errorprone('com.google.errorprone:error_prone_core:2.22.0') } } } From 74579b284b2a2ac5fcf4deb35b53f992d3c3f158 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Mon, 9 Oct 2023 11:55:12 -0400 Subject: [PATCH 117/240] Update metrics sample (#534) * Update metrics sample Signed-off-by: Tihomir Surdilovic * try to fix comment formatting violation Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- .../samples/metrics/MetricsStarter.java | 2 +- .../samples/metrics/MetricsUtils.java | 2 +- .../samples/metrics/MetricsWorker.java | 2 +- .../io/temporal/samples/metrics/README.md | 4 ++-- .../activities/MetricsActivitiesImpl.java | 21 ++++++++++++++++++- .../metrics/workflow/MetricsWorkflowImpl.java | 11 ++++++++++ .../temporal/samples/metrics/MetricsTest.java | 2 +- 7 files changed, 37 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java index bc31e3238..4989e765e 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java @@ -49,7 +49,7 @@ public static void main(String[] args) { .reporter(new MicrometerClientStatsReporter(registry)) .reportEvery(com.uber.m3.util.Duration.ofSeconds(1)); // Start the prometheus scrape endpoint for starter metrics - HttpServer scrapeEndpoint = MetricsUtils.startPrometheusScrapeEndpoint(registry, 8081); + HttpServer scrapeEndpoint = MetricsUtils.startPrometheusScrapeEndpoint(registry, 8078); // Stopping the starter will stop the http server that exposes the // scrape endpoint. Runtime.getRuntime().addShutdownHook(new Thread(() -> scrapeEndpoint.stop(1))); diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java b/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java index 9991e7994..03c20d481 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java @@ -38,7 +38,7 @@ public static HttpServer startPrometheusScrapeEndpoint( try { HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); server.createContext( - "/prometheus", + "/metrics", httpExchange -> { String response = registry.scrape(); httpExchange.sendResponseHeaders(200, response.getBytes(UTF_8).length); diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java index 258a0d689..609e60abb 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java @@ -56,7 +56,7 @@ public static void main(String[] args) { .reporter(new MicrometerClientStatsReporter(registry)) .reportEvery(com.uber.m3.util.Duration.ofSeconds(1)); // Start the prometheus scrape endpoint - HttpServer scrapeEndpoint = MetricsUtils.startPrometheusScrapeEndpoint(registry, 8080); + HttpServer scrapeEndpoint = MetricsUtils.startPrometheusScrapeEndpoint(registry, 8077); // Stopping the worker will stop the http server that exposes the // scrape endpoint. Runtime.getRuntime().addShutdownHook(new Thread(() -> scrapeEndpoint.stop(1))); diff --git a/core/src/main/java/io/temporal/samples/metrics/README.md b/core/src/main/java/io/temporal/samples/metrics/README.md index 7e0e5b25d..6ff6d9dcb 100644 --- a/core/src/main/java/io/temporal/samples/metrics/README.md +++ b/core/src/main/java/io/temporal/samples/metrics/README.md @@ -12,8 +12,8 @@ This sample shows setup for SDK metrics. ./gradlew -q execute -PmainClass=io.temporal.samples.metrics.MetricsStarter ``` -3. See the worker metrics on the exposed Prometheus Scrape Endpoint: [http://localhost:8080/prometheus](http://localhost:8080/prometheus) +3. See the worker metrics on the exposed Prometheus Scrape Endpoint: [http://localhost:8077/metrics](http://localhost:8077/metrics) -4. See the starter metrics on the exposed Prometheus Scrape Endpoint [http://localhost:8081/prometheus](http://localhost:8081/prometheus) +4. See the starter metrics on the exposed Prometheus Scrape Endpoint [http://localhost:8078/metrics](http://localhost:8078/metrics) 5. Stop the worker and starter diff --git a/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java b/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java index e47d1cf96..1844a44e8 100644 --- a/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java @@ -45,6 +45,25 @@ public String performB(String input) { } private void incRetriesCustomMetric(ActivityExecutionContext context) { - context.getMetricsScope().counter("activity_retries").inc(1); + // We can create a child scope and add extra tags + // Scope scope = + // context + // .getMetricsScope() + // .tagged( + // Stream.of( + // new String[][] { + // {"workflow_id", context.getInfo().getWorkflowId()}, + // {"activity_id", context.getInfo().getActivityId()}, + // { + // "activity_start_to_close_timeout", + // context.getInfo().getStartToCloseTimeout().toString() + // }, + // }) + // .collect(Collectors.toMap(data -> data[0], data -> data[1]))); + // + // scope.counter("custom_activity_retries").inc(1); + + // For sample we use root scope + context.getMetricsScope().counter("custom_activity_retries").inc(1); } } diff --git a/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java b/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java index 12e5f8dc4..560d013d6 100644 --- a/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java @@ -19,10 +19,12 @@ package io.temporal.samples.metrics.workflow; +import com.uber.m3.tally.Scope; import io.temporal.activity.ActivityOptions; import io.temporal.samples.metrics.activities.MetricsActivities; import io.temporal.workflow.Workflow; import java.time.Duration; +import java.util.Collections; public class MetricsWorkflowImpl implements MetricsWorkflow { @@ -33,6 +35,15 @@ public class MetricsWorkflowImpl implements MetricsWorkflow { @Override public String exec(String input) { + /* + * Custom metric, we can use child scope and attach workflow_id as it's not attached by default + * like task_queue ,workflow_type, etc + */ + Scope scope = + Workflow.getMetricsScope() + .tagged(Collections.singletonMap("workflow_id", Workflow.getInfo().getWorkflowId())); + scope.counter("custom_metric").inc(1); + String result = activities.performA(input); Workflow.sleep(Duration.ofSeconds(5)); result += activities.performB(input); diff --git a/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java b/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java index 4c593cb8a..86b13b3b6 100644 --- a/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java +++ b/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java @@ -151,7 +151,7 @@ private Counter countMetricActivityRetriesForActivity(String performB) { "ActivityWorker", SDK_CUSTOM_KEY, SDK_CUSTOM_VALUE); - return registry.counter("activity_retries", tags); + return registry.counter("custom_activity_retries", tags); } private void assertIntCounter(int expectedValue, Counter counter) { From d6eed631df64160e0a20b54e1fd7664cb20f29c0 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 11 Oct 2023 09:17:28 -0700 Subject: [PATCH 118/240] Update Java SDK to v1.22.0 (#537) Update Java SDK to v1.22.0 --- build.gradle | 2 +- core/src/test/java/io/temporal/samples/tracing/TracingTest.java | 2 +- .../springboot/TemporalSpringbootSamplesApplication.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 935272568..be5d04b4f 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.21.1' + javaSDKVersion = '1.22.0' jarVersion = '1.0.0' } diff --git a/core/src/test/java/io/temporal/samples/tracing/TracingTest.java b/core/src/test/java/io/temporal/samples/tracing/TracingTest.java index ef95cb3e4..e0baa2b94 100644 --- a/core/src/test/java/io/temporal/samples/tracing/TracingTest.java +++ b/core/src/test/java/io/temporal/samples/tracing/TracingTest.java @@ -96,6 +96,6 @@ public void testReportSpans() { List reportedSpans = reporter.getSpans(); assertNotNull(reportedSpans); - assertTrue(reportedSpans.size() == 6); + assertEquals(7, reportedSpans.size()); } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java b/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java index 88ca068a1..132464afc 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java @@ -25,6 +25,6 @@ @SpringBootApplication public class TemporalSpringbootSamplesApplication { public static void main(String[] args) { - SpringApplication.run(TemporalSpringbootSamplesApplication.class, args).start(); + SpringApplication.run(TemporalSpringbootSamplesApplication.class, args); } } From 62ad648683f5dcb662adf21a5dfc230ae0332655 Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Tue, 24 Oct 2023 09:49:38 -0400 Subject: [PATCH 119/240] Moneytransfer: Fixed worker variable name and unit test logging (#541) * Updated worker name * Fixed unit TransferWorkflowTest variable name typo --- .../samples/moneytransfer/AccountTransferWorker.java | 4 ++-- .../samples/moneytransfer/TransferWorkflowTest.java | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java index e35aa6ba9..b7aaf0fad 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java @@ -38,8 +38,8 @@ public static void main(String[] args) { // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); - Worker workerForCommonTaskQueue = factory.newWorker(TASK_QUEUE); - workerForCommonTaskQueue.registerWorkflowImplementationTypes(AccountTransferWorkflowImpl.class); + Worker worker = factory.newWorker(TASK_QUEUE); + worker.registerWorkflowImplementationTypes(AccountTransferWorkflowImpl.class); // Start all workers created by this factory. factory.start(); System.out.println("Worker started for task queue: " + TASK_QUEUE); diff --git a/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java b/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java index 8224d6dbb..f69fea2b2 100644 --- a/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java @@ -50,12 +50,14 @@ public void testTransfer() { testWorkflowRule .getWorkflowClient() .newWorkflowStub(AccountTransferWorkflow.class, options); - long starty = testWorkflowRule.getTestEnvironment().currentTimeMillis(); + + long start = testWorkflowRule.getTestEnvironment().currentTimeMillis(); workflow.transfer("account1", "account2", "reference1", 123); + long duration = testWorkflowRule.getTestEnvironment().currentTimeMillis() - start; + System.out.println("Duration hours: " + duration / 3600000); + verify(activities).withdraw(eq("account1"), eq("reference1"), eq(123)); verify(activities).deposit(eq("account2"), eq("reference1"), eq(123)); - long duration = testWorkflowRule.getTestEnvironment().currentTimeMillis() - starty; - System.out.println("Duration: " + duration); testWorkflowRule.getTestEnvironment().shutdown(); } From 98e7971749e62068bf0070f6c9a46c4a070f3024 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 10:37:21 -0400 Subject: [PATCH 120/240] Bump com.diffplug.spotless from 6.21.0 to 6.22.0 (#532) Bumps com.diffplug.spotless from 6.21.0 to 6.22.0. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index be5d04b4f..a33b05e0f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.1.0" - id 'com.diffplug.spotless' version '6.21.0' apply false + id 'com.diffplug.spotless' version '6.22.0' apply false id 'org.springframework.boot' version '2.7.13' } From 69f089d81a4f42f0c5fcfe30a201d54db08c5129 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 10:37:43 -0400 Subject: [PATCH 121/240] Bump org.junit:junit-bom from 5.9.3 to 5.10.0 (#533) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.9.3 to 5.10.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.0) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 209477ddf..9369e920f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -39,7 +39,7 @@ dependencies { testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:5.5.0" - testImplementation(platform("org.junit:junit-bom:5.9.3")) + testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation "org.junit.jupiter:junit-jupiter-api" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" testRuntimeOnly "org.junit.vintage:junit-vintage-engine" From 5be301772d7721b9ef7146ed06014e4d67c81b53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 10:38:05 -0400 Subject: [PATCH 122/240] Bump org.mockito:mockito-core from 5.5.0 to 5.6.0 (#535) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.5.0 to 5.6.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.5.0...v5.6.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 9369e920f..73276afe9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation 'com.codingrodent:jackson-json-crypto:1.1.0' testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.5.0" + testImplementation "org.mockito:mockito-core:5.6.0" testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation "org.junit.jupiter:junit-jupiter-api" From 50a6ebdeed7292f99c75c76c6dcef082f53c3121 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 10:43:34 -0400 Subject: [PATCH 123/240] Bump com.fasterxml.jackson:jackson-bom from 2.15.2 to 2.15.3 (#540) Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.15.2 to 2.15.3. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.15.2...jackson-bom-2.15.3) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 73276afe9..df5809b91 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:$javaSDKVersion") // Needed for SDK related functionality - implementation(platform("com.fasterxml.jackson:jackson-bom:2.15.2")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.15.3")) implementation "com.fasterxml.jackson.core:jackson-databind" implementation "com.fasterxml.jackson.core:jackson-core" From 4d6427dbd7bbc23e22cbf1bbcbcc04d3913c27e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Wed, 1 Nov 2023 13:57:56 +0100 Subject: [PATCH 124/240] Example with untyped child workflow started async (#543) * wip * wip * wip * wip * fix package name --- README.md | 2 + .../asyncuntypedchild/ChildWorkflow.java | 40 ++++++++ .../asyncuntypedchild/ChildWorkflowImpl.java | 40 ++++++++ .../asyncuntypedchild/ParentWorkflow.java | 40 ++++++++ .../asyncuntypedchild/ParentWorkflowImpl.java | 59 +++++++++++ .../samples/asyncuntypedchild/README.md | 8 ++ .../samples/asyncuntypedchild/Starter.java | 99 +++++++++++++++++++ .../AsyncUntypedChildTest.java | 99 +++++++++++++++++++ .../samples/hello/HelloChildTest.java | 2 +- .../samples/hello/HelloExceptionTest.java | 2 +- 10 files changed, 389 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/asyncuntypedchild/README.md create mode 100644 core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java create mode 100644 core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java diff --git a/README.md b/README.md index b5a82bdd4..b95e17a56 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman #### API demonstrations +- [**Async Untyped Child Workflow**](/core/src/main/java/io/temporal/samples/asyncuntypedchild): Demonstrates how to invoke an untyped child workflow async, that can complete after parent workflow is already completed. + - [**Updatable Timer**](/core/src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. - [**Workflow Count Interceptor**](/core/src/main/java/io/temporal/samples/countinterceptor): Demonstrates how to create and register a simple Workflow Count Interceptor. diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflow.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflow.java new file mode 100644 index 000000000..9cd9d75d2 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflow.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.asyncuntypedchild; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +/** + * Define the child workflow Interface. It must contain one method annotated with @WorkflowMethod + * + * @see WorkflowInterface + * @see WorkflowMethod + */ +@WorkflowInterface +public interface ChildWorkflow { + + /** + * Define the child workflow method. This method is executed when the workflow is started. The + * workflow completes when the workflow method finishes execution. + */ + @WorkflowMethod + String composeGreeting(String greeting, String name); +} diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflowImpl.java new file mode 100644 index 000000000..958bd0fc3 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflowImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.asyncuntypedchild; + +import io.temporal.workflow.Workflow; + +/** + * Define the parent workflow implementation. It implements the getGreeting workflow method + * + *

Note that a workflow implementation must always be public for the Temporal library to be able + * to create its instances. + */ +public class ChildWorkflowImpl implements ChildWorkflow { + + @Override + public String composeGreeting(String greeting, String name) { + + // Sleep for 2 seconds to ensure the child completes after the parent. + Workflow.sleep(2000); + + return greeting + " " + name + "!"; + } +} diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java new file mode 100644 index 000000000..b911ed234 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.asyncuntypedchild; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +/** + * Define the parent workflow interface. It must contain one method annotated with @WorkflowMethod + * + * @see WorkflowInterface + * @see WorkflowMethod + */ +@WorkflowInterface +public interface ParentWorkflow { + + /** + * Define the parent workflow method. This method is executed when the workflow is started. The + * workflow completes when the workflow method finishes execution. + */ + @WorkflowMethod + String getGreeting(String name); +} diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflowImpl.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflowImpl.java new file mode 100644 index 000000000..87cb9fd0f --- /dev/null +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflowImpl.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.asyncuntypedchild; + +import static io.temporal.samples.asyncuntypedchild.Starter.WORKFLOW_ID; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.ParentClosePolicy; +import io.temporal.workflow.*; + +// Define the parent workflow implementation. It implements the getGreeting workflow method +public class ParentWorkflowImpl implements ParentWorkflow { + + @Override + public String getGreeting(String name) { + /* + * Define the child workflow stub. Since workflows are stateful, + * a new stub must be created for each child workflow. + */ + ChildWorkflowStub child = + Workflow.newUntypedChildWorkflowStub( + ChildWorkflow.class.getSimpleName(), + ChildWorkflowOptions.newBuilder() + .setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON) + .setWorkflowId("Child_of_" + WORKFLOW_ID) + .build()); + + /* + * Invoke the child workflows composeGreeting workflow method async. + * This call is non-blocking and returns immediately returning a {@link io.temporal.workflow.Promise}, + * you can invoke `get()` on the returned promise to wait for the child workflow result. + */ + child.executeAsync(String.class, "Hello", name); + + // Wait for the child workflow to start before returning the result + Promise childExecution = child.getExecution(); + WorkflowExecution childWorkflowExecution = childExecution.get(); + + // return the child workflowId + return childWorkflowExecution.getWorkflowId(); + } +} diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/README.md b/core/src/main/java/io/temporal/samples/asyncuntypedchild/README.md new file mode 100644 index 000000000..0267240dc --- /dev/null +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/README.md @@ -0,0 +1,8 @@ +# Async Child Workflow execution + +The sample demonstrates shows how to invoke an Untyped Child Workflow asynchronously. +The Child Workflow continues running for some time after the Parent Workflow completes. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.asyncuntypedchild.Starter +``` diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java new file mode 100644 index 000000000..2453376ce --- /dev/null +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.asyncuntypedchild; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +/** + * Sample Temporal Workflow Definition that demonstrates the execution of a Child Workflow. Child + * workflows allow you to group your Workflow logic into small logical and reusable units that solve + * a particular problem. They can be typically reused by multiple other Workflows. + */ +public class Starter { + + static final String WORKFLOW_ID = "ParentWithAsyncUntypedChild"; + + static final String TASK_QUEUE = WORKFLOW_ID + "Queue"; + + /** + * With the workflow, and child workflow defined, we can now start execution. The main method is + * the workflow starter. + */ + public static void main(String[] args) { + + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register the parent and child workflow implementation with the worker. + * Since workflows are stateful in nature, + * we need to register the workflow types. + */ + worker.registerWorkflowImplementationTypes(ParentWorkflowImpl.class, ChildWorkflowImpl.class); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + // Start a workflow execution. Usually this is done from another program. + // Uses task queue from the GreetingWorkflow @WorkflowMethod annotation. + + // Create our parent workflow client stub. It is used to start the parent workflow execution. + ParentWorkflow workflow = + client.newWorkflowStub( + ParentWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + // Execute our parent workflow and wait for it to complete, it returns the child workflow id. + String childWorkflowId = workflow.getGreeting("World"); + System.out.println("Child WorkflowId=[" + childWorkflowId + "] started in abandon mode"); + + String childResult = client.newUntypedWorkflowStub(childWorkflowId).getResult(String.class); + + System.out.println("Result from child workflow = " + childResult); + + System.exit(0); + } +} diff --git a/core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java b/core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java new file mode 100644 index 000000000..12281dbcf --- /dev/null +++ b/core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.asyncuntypedchild; + +import static io.temporal.api.enums.v1.WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_RUNNING; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.*; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.WorkflowExecutionStatus; +import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionRequest; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.testing.TestWorkflowRule; +import org.jetbrains.annotations.NotNull; +import org.junit.Rule; +import org.junit.Test; + +/** Unit test for {@link ParentWorkflowImpl}. Doesn't use an external Temporal service. */ +public class AsyncUntypedChildTest { + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder().setDoNotStart(true).build(); + + @Test + public void testMockedChild() { + testWorkflowRule.getWorker().registerWorkflowImplementationTypes(ParentWorkflowImpl.class); + + // Factory is called to create a new workflow object on each workflow task. + testWorkflowRule + .getWorker() + .registerWorkflowImplementationFactory( + ChildWorkflow.class, + () -> { + ChildWorkflow child = mock(ChildWorkflow.class); + when(child.composeGreeting("Hello", "World")) + .thenReturn("Hello World from mocked child!"); + return child; + }); + + testWorkflowRule.getTestEnvironment().start(); + + // Get a workflow stub using the same task queue the worker uses. + WorkflowClient workflowClient = testWorkflowRule.getWorkflowClient(); + ParentWorkflow workflow = + workflowClient.newWorkflowStub( + ParentWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + // Execute the parent workflow and wait for it to complete. + String childWorkflowId = workflow.getGreeting("World"); + assertNotNull(childWorkflowId); + + assertEquals( + WORKFLOW_EXECUTION_STATUS_RUNNING, + getChildWorkflowExecutionStatus(workflowClient, childWorkflowId)); + + // Wait for the child to complete + String childResult = + workflowClient.newUntypedWorkflowStub(childWorkflowId).getResult(String.class); + assertEquals("Hello World from mocked child!", childResult); + + testWorkflowRule.getTestEnvironment().shutdown(); + } + + @NotNull + private WorkflowExecutionStatus getChildWorkflowExecutionStatus( + WorkflowClient workflowClient, String childWorkflowId) { + return workflowClient + .getWorkflowServiceStubs() + .blockingStub() + .describeWorkflowExecution( + DescribeWorkflowExecutionRequest.newBuilder() + .setNamespace(testWorkflowRule.getTestEnvironment().getNamespace()) + .setExecution(WorkflowExecution.newBuilder().setWorkflowId(childWorkflowId).build()) + .build()) + .getWorkflowExecutionInfo() + .getStatus(); + } +} diff --git a/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java b/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java index 9c76a12db..829f4aa10 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java @@ -70,7 +70,7 @@ public void testMockedChild() { // Factory is called to create a new workflow object on each workflow task. testWorkflowRule .getWorker() - .addWorkflowImplementationFactory( + .registerWorkflowImplementationFactory( GreetingChild.class, () -> { GreetingChild child = mock(GreetingChild.class); diff --git a/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java b/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java index 84f95fa6d..7fef3c8b1 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java @@ -119,7 +119,7 @@ public void testChildWorkflowTimeout() { // Mock a child that times out. testWorkflowRule .getWorker() - .addWorkflowImplementationFactory( + .registerWorkflowImplementationFactory( HelloException.GreetingChild.class, () -> { GreetingChildImpl child = mock(GreetingChildImpl.class); From d22b4164cc752931c827f79e092acbe315a71f50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:35:17 -0500 Subject: [PATCH 125/240] Bump javaSDKVersion from 1.22.0 to 1.22.2 (#545) Bumps `javaSDKVersion` from 1.22.0 to 1.22.2. Updates `io.temporal:temporal-sdk` from 1.22.0 to 1.22.2 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.22.0...v1.22.2) Updates `io.temporal:temporal-opentracing` from 1.22.0 to 1.22.2 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.22.0...v1.22.2) Updates `io.temporal:temporal-testing` from 1.22.0 to 1.22.2 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.22.0...v1.22.2) Updates `io.temporal:temporal-spring-boot-starter-alpha` from 1.22.0 to 1.22.2 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.22.0...v1.22.2) --- updated-dependencies: - dependency-name: io.temporal:temporal-sdk dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-opentracing dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-testing dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-spring-boot-starter-alpha dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a33b05e0f..75b8d0cde 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.22.0' + javaSDKVersion = '1.22.2' jarVersion = '1.0.0' } From 98b5976c2613285361d1ae023df9145491468c3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:35:45 -0500 Subject: [PATCH 126/240] Bump org.junit:junit-bom from 5.10.0 to 5.10.1 (#546) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.10.0 to 5.10.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.0...r5.10.1) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index df5809b91..b4b872293 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -39,7 +39,7 @@ dependencies { testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:5.6.0" - testImplementation(platform("org.junit:junit-bom:5.10.0")) + testImplementation(platform("org.junit:junit-bom:5.10.1")) testImplementation "org.junit.jupiter:junit-jupiter-api" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" testRuntimeOnly "org.junit.vintage:junit-vintage-engine" From ebf633f303ad1e05de004a43c857400f7a830580 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:36:23 -0500 Subject: [PATCH 127/240] Bump com.google.errorprone:error_prone_core from 2.22.0 to 2.23.0 (#547) Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.22.0 to 2.23.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.22.0...v2.23.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- springboot/build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index b4b872293..6e0f5f9dc 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -46,7 +46,7 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.22.0') + errorprone('com.google.errorprone:error_prone_core:2.23.0') } } diff --git a/springboot/build.gradle b/springboot/build.gradle index 78eccd063..6f09712a7 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -15,9 +15,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.22.0') + errorprone('com.google.errorprone:error_prone_core:2.23.0') } else { - errorprone('com.google.errorprone:error_prone_core:2.22.0') + errorprone('com.google.errorprone:error_prone_core:2.23.0') } } } From caea5baa2df01b04852cc5f2c883fc9686494251 Mon Sep 17 00:00:00 2001 From: Joe Antony Date: Mon, 4 Dec 2023 16:16:25 +0530 Subject: [PATCH 128/240] Update README in retryonsignalinterceptor/ with correct class names (#550) --- .../io/temporal/samples/retryonsignalinterceptor/README.MD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD index ab46ac1df..95ae325a7 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD @@ -6,17 +6,17 @@ fail or retry. Starts Worker. The worker upon start initiates a workflow that has an activity that fails on the fist invocation. ```bash -./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.Worker +./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker ``` Sends Signal to indicate that the activity should be retried. ```bash -./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.RetryActivity +./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.RetryRequester ``` Sends a signal to propagate the activity failure to the workflow instead of retrying. ```bash -./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.FailActivity +./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.FailureRequester ``` From 7a2740aba6ee749658759781bf1ef30991a4a162 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:47:37 -0500 Subject: [PATCH 129/240] Bump org.mockito:mockito-core from 5.6.0 to 5.8.0 (#553) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.6.0 to 5.8.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.6.0...v5.8.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 6e0f5f9dc..2dd0452c5 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation 'com.codingrodent:jackson-json-crypto:1.1.0' testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.6.0" + testImplementation "org.mockito:mockito-core:5.8.0" testImplementation(platform("org.junit:junit-bom:5.10.1")) testImplementation "org.junit.jupiter:junit-jupiter-api" From ff8bdb453e1ee6134251643d17e26fc436965165 Mon Sep 17 00:00:00 2001 From: "mend-for-github-com[bot]" <50673670+mend-for-github-com[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:49:30 -0500 Subject: [PATCH 130/240] Update dependency ch.qos.logback:logback-classic to v1.4.12 (#556) Co-authored-by: mend-for-github-com[bot] <50673670+mend-for-github-com[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 2dd0452c5..998aa476c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.11' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.12' implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) From a47b3b6ba76854a11f1a56c249ece0cf2cd85385 Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Mon, 18 Dec 2023 20:06:53 -0800 Subject: [PATCH 131/240] Added HelloAwait sample (#565) * Added HelloAwait sample * missed changes --- README.md | 1 + .../io/temporal/samples/hello/HelloAwait.java | 159 ++++++++++++++++++ .../samples/hello/HelloAwaitTest.java | 104 ++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloAwait.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloAwaitTest.java diff --git a/README.md b/README.md index b95e17a56..f7846128f 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloActivityRetry**](/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java): Demonstrates how to Retry an Activity Execution. - [**HelloActivityExclusiveChoice**](/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java): Demonstrates how to execute Activities based on dynamic input. - [**HelloAsync**](/core/src/main/java/io/temporal/samples/hello/HelloAsync.java): Demonstrates how to execute Activities asynchronously and wait for them using Promises. + - [**HelloAwait**](/core/src/main/java/io/temporal/samples/hello/HelloAwait.java): Demonstrates how to use Await statement to wait for a condition. - [**HelloParallelActivity**](/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java): Demonstrates how to execute multiple Activities in parallel, asynchronously, and wait for them using `Promise.allOf`. - [**HelloAsyncActivityCompletion**](/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java): Demonstrates how to complete an Activity Execution asynchronously. - [**HelloAsyncLambda**](/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java): Demonstrates how to execute part of a Workflow asynchronously in a separate task (thread). diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAwait.java b/core/src/main/java/io/temporal/samples/hello/HelloAwait.java new file mode 100644 index 000000000..5868534c8 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloAwait.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.ApplicationFailure; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.time.Duration; + +/** + * Sample Temporal workflow that demonstrates how to use workflow await methods to wait up to a + * specified timeout for a condition updated from a signal handler. + */ +public class HelloAwait { + + // Define the task queue name + static final String TASK_QUEUE = "HelloAwaitTaskQueue"; + + // Define the workflow unique id + static final String WORKFLOW_ID = "HelloAwaitWorkflow"; + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see WorkflowInterface + * @see WorkflowMethod + */ + @WorkflowInterface + public interface GreetingWorkflow { + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + String getGreeting(); + + // Define the workflow waitForName signal method. This method is executed when the workflow + // receives a "WaitForName" signal. + @SignalMethod + void waitForName(String name); + } + + // Define the workflow implementation which implements the getGreetings workflow method. + public static class GreetingWorkflowImpl implements GreetingWorkflow { + + private String name; + + @Override + public String getGreeting() { + boolean ok = Workflow.await(Duration.ofSeconds(10), () -> name != null); + if (ok) { + return "Hello " + name + "!"; + } else { + // To fail workflow use ApplicationFailure. Any other exception would cause workflow to + // stall, not to fail. + throw ApplicationFailure.newFailure( + "WaitForName signal is not received within 10 seconds.", "signal-timeout"); + } + } + + @Override + public void waitForName(String name) { + this.name = name; + } + } + + /** + * With the Workflow and Activities defined, we can now start execution. The main method starts + * the worker and then the workflow. + */ + public static void main(String[] args) throws Exception { + + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Await, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register the workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + // Create the workflow options + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(WORKFLOW_ID).build(); + + // Create the workflow client stub. It is used to start the workflow execution. + GreetingWorkflow workflow = client.newWorkflowStub(GreetingWorkflow.class, workflowOptions); + + // Start workflow asynchronously and call its getGreeting workflow method + WorkflowClient.start(workflow::getGreeting); + + // After start for getGreeting returns, the workflow is guaranteed to be started. + // Send WaitForName signal. + workflow.waitForName("World"); + + /* + * Here we create a new untyped workflow stub using the same workflow id. + * The untyped stub is a convenient way to wait for a workflow result. + */ + WorkflowStub workflowById = client.newUntypedWorkflowStub(WORKFLOW_ID); + + String greeting = workflowById.getResult(String.class); + + System.out.println(greeting); + System.exit(0); + } +} diff --git a/core/src/test/java/io/temporal/samples/hello/HelloAwaitTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAwaitTest.java new file mode 100644 index 000000000..1912a942d --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloAwaitTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowException; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.ApplicationFailure; +import io.temporal.samples.hello.HelloAwait.GreetingWorkflow; +import io.temporal.testing.TestWorkflowRule; +import java.time.Duration; +import org.junit.Rule; +import org.junit.Test; + +/** Unit test for {@link HelloAwait}. Doesn't use an external Temporal service. */ +public class HelloAwaitTest { + + private final String WORKFLOW_ID = "WORKFLOW1"; + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder().setWorkflowTypes(HelloAwait.GreetingWorkflowImpl.class).build(); + + @Test + public void testAwaitSignal() { + // Get a workflow stub using the same task queue the worker uses. + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(WORKFLOW_ID) + .build(); + + GreetingWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(GreetingWorkflow.class, workflowOptions); + + // Start workflow asynchronously to not use another thread to await. + WorkflowClient.start(workflow::getGreeting); + workflow.waitForName("World"); + // So we can send a await to it using workflow stub immediately. + // But just to demonstrate the unit testing of a long running workflow adding a long sleep here. + // testWorkflowRule.getTestEnvironment().sleep(Duration.ofSeconds(30)); + + WorkflowStub workflowById = + testWorkflowRule.getWorkflowClient().newUntypedWorkflowStub(WORKFLOW_ID); + + String greeting = workflowById.getResult(String.class); + assertEquals("Hello World!", greeting); + } + + @Test + public void testAwaitTimeout() { + // Get a workflow stub using the same task queue the worker uses. + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(WORKFLOW_ID) + .build(); + + GreetingWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(GreetingWorkflow.class, workflowOptions); + + // Start workflow asynchronously to not use another thread to wait. + WorkflowClient.start(workflow::getGreeting); + + // Skip time to force Await timeout + testWorkflowRule.getTestEnvironment().sleep(Duration.ofSeconds(30)); + + WorkflowStub workflowById = + testWorkflowRule.getWorkflowClient().newUntypedWorkflowStub(WORKFLOW_ID); + + try { + workflowById.getResult(String.class); + fail("not reachable"); + } catch (WorkflowException e) { + ApplicationFailure applicationFailure = (ApplicationFailure) e.getCause(); + assertEquals("signal-timeout", applicationFailure.getType()); + } + } +} From 404adcbbc8486e99a7a28de266c738c337d32bca Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Thu, 28 Dec 2023 22:11:58 -0500 Subject: [PATCH 132/240] update to SpringBoot 3 (#564) * update to SpringBoot 3 Signed-off-by: Tihomir Surdilovic * allow support for both spring boot 2 and 3 Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 10 +++++++--- build.gradle | 36 +++++++++++++++++++----------------- gradle.properties | 4 ++++ springboot/build.gradle | 6 +----- 4 files changed, 31 insertions(+), 25 deletions(-) create mode 100644 gradle.properties diff --git a/README.md b/README.md index f7846128f..320be8f4f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Temporal using the [Java SDK](https://github.com/temporalio/sdk-java). It contains two modules: * [Core](/core): showcases many different SDK features. -* [SpringBoot](/springboot): showcases springboot autoconfig integration. +* [SpringBoot](/springboot): showcases SpringBoot autoconfig integration. ## Learn more about Temporal and Java SDK @@ -15,8 +15,9 @@ It contains two modules: ## Requirements -- Java 1.8+ for build and runtime -- Java 11+ for development and contribution +- Java 1.8+ for build and runtime of core samples +- Java 1.8+ for build and runtime of SpringBoot samples when using SpringBoot 2 +- Java 1.17+ for build and runtime of Spring Boot samples when using SpringBoot 3 - Local Temporal Server, easiest to get started would be using [Temporal CLI](https://github.com/temporalio/cli). For more options see docs [here](https://docs.temporal.io/kb/all-the-ways-to-run-a-cluster). @@ -133,6 +134,9 @@ See the README.md file in each main sample directory for cut/paste Gradle comman ### Running SpringBoot Samples +These samples use SpringBoot 2 by default. To switch to using SpringBoot 3 look at the [gradle.properties](gradle.properties) file +and follow simple instructions there. + 1. Start SpringBoot from main repo dir: ./gradlew bootRun diff --git a/build.gradle b/build.gradle index 75b8d0cde..663a8f2dc 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.1.0" id 'com.diffplug.spotless' version '6.22.0' apply false - id 'org.springframework.boot' version '2.7.13' + id "org.springframework.boot" version "${springBootPluginVersion}" } subprojects { @@ -11,15 +11,20 @@ subprojects { apply plugin: 'net.ltgt.errorprone' apply plugin: 'com.diffplug.spotless' - java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - compileJava { options.compilerArgs << "-Werror" } + java { + if(project.property("springBootPluginVersion") == "2.7.13") { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } else { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + } + ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" @@ -47,21 +52,18 @@ subprojects { exclude '**/*.js' } - if (JavaVersion.current().isJava11Compatible()) { - // Code should be formatted using the latest googleJavaFormat, but it doesn't support Java <11 since version 1.8 - apply plugin: 'com.diffplug.spotless' + apply plugin: 'com.diffplug.spotless' - spotless { - java { - target 'src/*/java/**/*.java' - targetExclude '**/.idea/**' - googleJavaFormat('1.16.0') - } + spotless { + java { + target 'src/*/java/**/*.java' + targetExclude '**/.idea/**' + googleJavaFormat('1.16.0') } - - compileJava.dependsOn 'spotlessApply' } + compileJava.dependsOn 'spotlessApply' + test { useJUnitPlatform() } diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..288738795 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,4 @@ +springBootPluginVersion=2.7.13 + +# use this for spring boot 3 support +#springBootPluginVersion=3.2.0 diff --git a/springboot/build.gradle b/springboot/build.gradle index 6f09712a7..569e1cc91 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -14,11 +14,7 @@ dependencies { testImplementation "org.springframework.boot:spring-boot-starter-test" dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.23.0') - } else { - errorprone('com.google.errorprone:error_prone_core:2.23.0') - } + errorprone('com.google.errorprone:error_prone_core:2.23.0') } } From 10e1376671094715f7b32f1b9c180da607ecfa3b Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Fri, 29 Dec 2023 23:28:57 -0500 Subject: [PATCH 133/240] Hello delayed start sample (#569) * update to SpringBoot 3 Signed-off-by: Tihomir Surdilovic * hello delayed start sample Signed-off-by: Tihomir Surdilovic * fix Signed-off-by: Tihomir Surdilovic * fix comment Signed-off-by: Tihomir Surdilovic * update to readme Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 1 + .../samples/hello/HelloDelayedStart.java | 131 ++++++++++++++++++ .../samples/hello/HelloDelayedStartTest.java | 69 +++++++++ 3 files changed, 201 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloDelayedStartTest.java diff --git a/README.md b/README.md index 320be8f4f..4d3c226d1 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloSearchAttributes**](/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java): Demonstrates how to add custom Search Attributes to Workflow Executions. - [**HelloSideEffect**](/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. - [**HelloUpdate**](/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java): Demonstrates how to create and interact with an Update. + - [**HelloDelayedStart**](/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java): Demonstrates how to use delayed start config option when starting a Workflow Executions. #### Scenario-based samples diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java b/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java new file mode 100644 index 000000000..a0b850854 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.WorkflowExecutionHistory; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.time.Duration; + +/** Sample Temporal Workflow Definition that shows how to use delayed start. */ +public class HelloDelayedStart { + // Define the task queue name + static final String TASK_QUEUE = "HelloDelayedStartTaskQueue"; + + // Define our workflow unique id + static final String WORKFLOW_ID = "HelloDelayedStartWorkflow"; + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see io.temporal.workflow.WorkflowInterface + * @see io.temporal.workflow.WorkflowMethod + */ + @WorkflowInterface + public interface DelayedStartWorkflow { + + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + void start(); + } + + // Define the workflow implementation which implements our start workflow method. + public static class DelayedStartWorkflowImpl implements DelayedStartWorkflow { + @Override + public void start() { + // this workflow just sleeps for a second + Workflow.sleep(Duration.ofSeconds(1)); + } + } + + public static void main(String[] args) { + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register our workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(DelayedStartWorkflowImpl.class); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + DelayedStartWorkflow workflow = + client.newWorkflowStub( + DelayedStartWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + // set delayed start in 2 seconds + .setStartDelay(Duration.ofSeconds(2)) + .build()); + + workflow.start(); + + // Delayed executions are still created right away by the service but + // they have a firstWorkflowTaskBackoff set to the delay duration + // meaning the first workflow task is dispatched by service + // 2 second after exec is started in our sample + WorkflowExecutionHistory history = client.fetchHistory(WORKFLOW_ID); + com.google.protobuf.Duration backoff = + history + .getHistory() + .getEvents(0) + .getWorkflowExecutionStartedEventAttributes() + .getFirstWorkflowTaskBackoff(); + System.out.println("First workflow task backoff: " + backoff.getSeconds()); + + System.exit(0); + } +} diff --git a/core/src/test/java/io/temporal/samples/hello/HelloDelayedStartTest.java b/core/src/test/java/io/temporal/samples/hello/HelloDelayedStartTest.java new file mode 100644 index 000000000..273b351e8 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloDelayedStartTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static org.junit.Assert.assertEquals; + +import io.temporal.client.WorkflowOptions; +import io.temporal.common.WorkflowExecutionHistory; +import io.temporal.testing.TestWorkflowRule; +import java.time.Duration; +import org.junit.Rule; +import org.junit.Test; + +public class HelloDelayedStartTest { + private final String WORKFLOW_ID = "HelloDelayedStartWorkflow"; + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(HelloDelayedStart.DelayedStartWorkflowImpl.class) + .build(); + + @Test + public void testDelayedStart() { + // Get a workflow stub using the same task queue the worker uses. + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(WORKFLOW_ID) + .setStartDelay(Duration.ofSeconds(2)) + .build(); + + HelloDelayedStart.DelayedStartWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(HelloDelayedStart.DelayedStartWorkflow.class, workflowOptions); + + workflow.start(); + + // Fetch event history and make sure we got the 2 seconds first workflow task backoff + WorkflowExecutionHistory history = + testWorkflowRule.getWorkflowClient().fetchHistory(WORKFLOW_ID); + com.google.protobuf.Duration backoff = + history + .getHistory() + .getEvents(0) + .getWorkflowExecutionStartedEventAttributes() + .getFirstWorkflowTaskBackoff(); + + assertEquals(2, backoff.getSeconds()); + } +} From e2652fc01d0962abb5f290c89a9b1fff73816789 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Thu, 18 Jan 2024 13:37:53 -0500 Subject: [PATCH 134/240] update dsl sample readme (#571) Signed-off-by: Tihomir Surdilovic --- core/src/main/java/io/temporal/samples/dsl/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/dsl/README.md b/core/src/main/java/io/temporal/samples/dsl/README.md index d89dfade6..4ebcf8e02 100644 --- a/core/src/main/java/io/temporal/samples/dsl/README.md +++ b/core/src/main/java/io/temporal/samples/dsl/README.md @@ -5,8 +5,13 @@ This sample shows how to use a DSL on top of Temporal. The sample uses CNCF Serverless Workflow (serverlessworkflow.io) DSL and its Java SDK, which helps us parse the DSL into an object model as well as provides DSL validation. -Since this is just a sample, this sample provides only partial implementation of the -entire [Serverless Workflow](https://serverlessworkflow.io/) DSL features. +Note: Temporal helps you to focus on business logic. We handle the complexities of building scalable distributed systems so you can deliver reliable workflows faster. +Our approach helps you build the tooling you need, without restricting functionality. +As with all samples, use the following at your own risk. +Temporal does not endorse the use of CNCF Serverless Workflows; the following code is just an example. +As a rule, DSLs provide limited and restrictive functionality. +They are not suitable for full expressive development. +In many cases, it's better to build customized DSLs to optimize simplicity and domain targeting for your particular use case. This sample runs the following DSL workflows: 1. [`customerapplication/workflow.yml`](../../../../../resources/dsl/customerapplication/workflow.yml) From a3c19c5cacb4c7969078f4120d66f06414a859c4 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Fri, 26 Jan 2024 17:23:21 -0500 Subject: [PATCH 135/240] add cancelation sample with workflow timer (#573) * add cancelation sample with workflow timer Signed-off-by: Tihomir Surdilovic * updated comment Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 1 + .../HelloCancellationScopeWithTimer.java | 231 ++++++++++++++++++ .../HelloCancellationScopeWithTimerTest.java | 51 ++++ 3 files changed, 283 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeWithTimerTest.java diff --git a/README.md b/README.md index 4d3c226d1..31828267c 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloAsyncActivityCompletion**](/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java): Demonstrates how to complete an Activity Execution asynchronously. - [**HelloAsyncLambda**](/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java): Demonstrates how to execute part of a Workflow asynchronously in a separate task (thread). - [**HelloCancellationScope**](/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java): Demonstrates how to explicitly cancel parts of a Workflow Execution. + - [**HelloCancellationScopeWithTimer**](/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java): Demonstrates how to cancel activity when workflow timer fires and complete execution. This can prefered over using workflow run/execution timeouts. - [**HelloDetachedCancellationScope**](/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java): Demonstrates how to execute cleanup code after a Workflow Execution has been explicitly cancelled. - [**HelloChild**](/core/src/main/java/io/temporal/samples/hello/HelloChild.java): Demonstrates how to execute a simple Child Workflow. - [**HelloCron**](/core/src/main/java/io/temporal/samples/hello/HelloCron.java): Demonstrates how to execute a Workflow according to a cron schedule. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java new file mode 100644 index 000000000..0f70bd814 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.activity.*; +import io.temporal.client.ActivityCompletionException; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.CanceledFailure; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.*; +import java.time.Duration; +import java.util.concurrent.TimeUnit; + +public class HelloCancellationScopeWithTimer { + // Define the task queue name + static final String TASK_QUEUE = "HelloCancellationScopeTimerTaskQueue"; + + // Define our workflow unique id + static final String WORKFLOW_ID = "HelloCancellationScopeTimerWorkflow"; + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see io.temporal.workflow.WorkflowInterface + * @see io.temporal.workflow.WorkflowMethod + */ + @WorkflowInterface + public interface CancellationWithTimerWorkflow { + + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + String execute(String input); + } + + /** + * This is the Activity Definition's Interface. Activities are building blocks of any Temporal + * Workflow and contain any business logic that could perform long running computation, network + * calls, etc. + * + *

Annotating Activity Definition methods with @ActivityMethod is optional. + * + * @see io.temporal.activity.ActivityInterface + * @see io.temporal.activity.ActivityMethod + */ + @ActivityInterface + public interface UpdateInfoActivities { + String updateInfo(String input); + } + + // Define the workflow implementation which implements our getGreeting workflow method. + public static class CancellationWithTimerWorkflowImpl implements CancellationWithTimerWorkflow { + private final UpdateInfoActivities activities = + Workflow.newActivityStub( + UpdateInfoActivities.class, + ActivityOptions.newBuilder() + // If heartbeat timeout is not set, activity heartbeats will be throttled to one + // every 30 seconds, it also will not have a heartbeat timeout. + .setHeartbeatTimeout(Duration.ofSeconds(2)) + .setStartToCloseTimeout(Duration.ofSeconds(10)) + .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED) + .build()); + + private String result; + + @Override + public String execute(String input) { + // Create cancellation scope for our activity execution + CancellationScope cancellationScope = + Workflow.newCancellationScope( + () -> { + try { + result = activities.updateInfo(input); + } catch (ActivityFailure cause) { + throw cause; + } + }); + + // Create a timer, if this timer fires we want to cancel our activity and complete the + // workflow execution + // Giving client default result. Note for sample the tier is set to less than the + // activity StartToClose timeout in order to simulate it getting cancelled + Workflow.newTimer(Duration.ofSeconds(3)) + .thenApply( + result -> { + // Cancel our activity, note activity has to heartbeat to receive cancellation + System.out.println("Cancelling scope as timer fired"); + cancellationScope.cancel(); + return null; + }); + // Start our cancellation scope + try { + cancellationScope.run(); + } catch (ActivityFailure e) { + // Activity cancellation is going thrigger activity failure + // The cause of activity failure would be CanceledFailure + if (e.getCause() instanceof CanceledFailure) { + result = "Activity canceled due to timer firing."; + } else { + result = "Activity failed due to: " + e.getMessage(); + } + } + return result; + } + } + + /** + * Implementation of our workflow activity interface. It overwrites our defined composeGreeting + * method. + */ + static class UpdateInfoActivitiesImpl implements UpdateInfoActivities { + + @Override + public String updateInfo(String input) { + // Get the activity execution context + ActivityExecutionContext context = Activity.getExecutionContext(); + + // Our "dummy" activity just sleeps for a second up to 10 times and heartbeats + for (int i = 0; i < 10; i++) { + sleep(1); + try { + context.heartbeat(i); + } catch (ActivityCompletionException e) { + // Here we can do some cleanup if needed before we re-throw activity completion exception + throw e; + } + } + + return "dummy activity result"; + } + + private void sleep(int seconds) { + try { + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); + } catch (InterruptedException ee) { + // Empty + } + } + } + + /** + * With our Workflow and Activities defined, we can now start execution. The main method starts + * the worker and then the workflow. + */ + public static void main(String[] args) { + + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register our workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(CancellationWithTimerWorkflowImpl.class); + + /* + * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, + * the Activity Type is a shared instance. + */ + worker.registerActivitiesImplementations(new UpdateInfoActivitiesImpl()); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + // Create the workflow client stub. It is used to start our workflow execution. + CancellationWithTimerWorkflow workflow = + client.newWorkflowStub( + CancellationWithTimerWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + /* + * Execute our workflow and wait for it to complete. The call to our getGreeting method is + * synchronous. + */ + String result = workflow.execute("Some test input"); + + // Display workflow execution results + System.out.println(result); + System.exit(0); + } +} diff --git a/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeWithTimerTest.java b/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeWithTimerTest.java new file mode 100644 index 000000000..4c6e2bd79 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeWithTimerTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static org.junit.Assert.assertTrue; + +import io.temporal.client.WorkflowOptions; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Rule; +import org.junit.Test; + +public class HelloCancellationScopeWithTimerTest { + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(HelloCancellationScopeWithTimer.CancellationWithTimerWorkflowImpl.class) + .setActivityImplementations( + new HelloCancellationScopeWithTimer.UpdateInfoActivitiesImpl()) + .build(); + + @Test(timeout = 240_000) + public void testActivityImpl() { + // Get a workflow stub using the same task queue the worker uses. + HelloCancellationScopeWithTimer.CancellationWithTimerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloCancellationScopeWithTimer.CancellationWithTimerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + // Execute a workflow waiting for it to complete. + String result = workflow.execute("Test Input"); + assertTrue(result.endsWith("Activity canceled due to timer firing.")); + } +} From 82c5f38b5a8adfdd611e1ec28d36439f3d2b1e0b Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Sun, 11 Feb 2024 16:40:17 -0800 Subject: [PATCH 136/240] Add basic SpringBoot sample (#574) --- .gitignore | 2 + README.md | 8 +- settings.gradle | 2 +- springboot-basic/build.gradle | 26 +++ .../samples/springboot/SamplesController.java | 61 ++++++ .../TemporalSpringbootSamplesApplication.java | 30 +++ .../springboot/hello/HelloActivity.java | 28 +++ .../springboot/hello/HelloActivityImpl.java | 38 ++++ .../springboot/hello/HelloWorkflow.java | 30 +++ .../springboot/hello/HelloWorkflowImpl.java | 40 ++++ .../samples/springboot/hello/README.md | 16 ++ .../springboot/hello/model/Person.java | 48 +++++ .../src/main/resources/application-tc.yaml | 9 + .../src/main/resources/application.yaml | 18 ++ .../main/resources/static/js/jquery.sse.js | 199 ++++++++++++++++++ .../main/resources/static/js/samplessse.js | 18 ++ .../main/resources/templates/fragments.html | 21 ++ .../src/main/resources/templates/hello.html | 56 +++++ .../src/main/resources/templates/index.html | 17 ++ .../samples/springboot/HelloSampleTest.java | 71 +++++++ .../src/test/resources/application.yaml | 21 ++ .../samples/springboot/customize/README.md | 2 +- .../samples/springboot/hello/README.md | 2 +- .../samples/springboot/kafka/README.md | 2 +- .../samples/springboot/metrics/README.md | 2 +- .../samples/springboot/update/README.md | 2 +- 26 files changed, 762 insertions(+), 7 deletions(-) create mode 100644 springboot-basic/build.gradle create mode 100644 springboot-basic/src/main/java/io/temporal/samples/springboot/SamplesController.java create mode 100644 springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java create mode 100644 springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java create mode 100644 springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java create mode 100644 springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java create mode 100644 springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java create mode 100644 springboot-basic/src/main/java/io/temporal/samples/springboot/hello/README.md create mode 100644 springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java create mode 100644 springboot-basic/src/main/resources/application-tc.yaml create mode 100644 springboot-basic/src/main/resources/application.yaml create mode 100644 springboot-basic/src/main/resources/static/js/jquery.sse.js create mode 100644 springboot-basic/src/main/resources/static/js/samplessse.js create mode 100644 springboot-basic/src/main/resources/templates/fragments.html create mode 100644 springboot-basic/src/main/resources/templates/hello.html create mode 100644 springboot-basic/src/main/resources/templates/index.html create mode 100644 springboot-basic/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java create mode 100644 springboot-basic/src/test/resources/application.yaml diff --git a/.gitignore b/.gitignore index 5b96932e2..87bc9f8e1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,11 @@ target /build /core/build /springboot/build +/springboot-basic/build /out /core/out /springboot/out +/springboot-basic/out .classpath .project .settings/ diff --git a/README.md b/README.md index 31828267c..f3ccce048 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Temporal using the [Java SDK](https://github.com/temporalio/sdk-java). It contains two modules: * [Core](/core): showcases many different SDK features. * [SpringBoot](/springboot): showcases SpringBoot autoconfig integration. +* [SpringBoot Basic](/springboot-basic): Minimal sample showing SpringBoot autoconfig integration without any extra external dependencies. ## Learn more about Temporal and Java SDK @@ -141,7 +142,12 @@ and follow simple instructions there. 1. Start SpringBoot from main repo dir: - ./gradlew bootRun + ./gradlew :springboot:bootRun + +To run the basic sample run + + ./gradlew :springboot-basic:bootRun + 2. Navigate to [localhost:3030](http://localhost:3030) diff --git a/settings.gradle b/settings.gradle index 4594514ab..65c976aaa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,4 @@ rootProject.name = 'temporal-java-samples' include 'core' include 'springboot' - +include 'springboot-basic' diff --git a/springboot-basic/build.gradle b/springboot-basic/build.gradle new file mode 100644 index 000000000..9d621e005 --- /dev/null +++ b/springboot-basic/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'org.springframework.boot' + +dependencies { + implementation "org.springframework.boot:spring-boot-starter-web" + implementation "org.springframework.boot:spring-boot-starter-thymeleaf" + implementation "org.springframework.boot:spring-boot-starter-actuator" + implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" + testImplementation "org.springframework.boot:spring-boot-starter-test" + runtimeOnly "io.micrometer:micrometer-registry-prometheus" + dependencies { + errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') + if (JavaVersion.current().isJava11Compatible()) { + errorprone('com.google.errorprone:error_prone_core:2.22.0') + } else { + errorprone('com.google.errorprone:error_prone_core:2.22.0') + } + } +} + +bootJar { + enabled = false +} + +jar { + enabled = true +} \ No newline at end of file diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/SamplesController.java new file mode 100644 index 000000000..79185cd67 --- /dev/null +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.springboot.hello.HelloWorkflow; +import io.temporal.samples.springboot.hello.model.Person; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +@Controller +public class SamplesController { + + @Autowired WorkflowClient client; + + @GetMapping("/hello") + public String hello(Model model) { + model.addAttribute("sample", "Say Hello"); + return "hello"; + } + + @PostMapping( + value = "/hello", + consumes = {MediaType.APPLICATION_JSON_VALUE}, + produces = {MediaType.TEXT_HTML_VALUE}) + ResponseEntity helloSample(@RequestBody Person person) { + HelloWorkflow workflow = + client.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("HelloSampleTaskQueue") + .setWorkflowId("HelloSample") + .build()); + + // bypass thymeleaf, don't return template name just result + return new ResponseEntity<>("\"" + workflow.sayHello(person) + "\"", HttpStatus.OK); + } +} diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java new file mode 100644 index 000000000..88ca068a1 --- /dev/null +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TemporalSpringbootSamplesApplication { + public static void main(String[] args) { + SpringApplication.run(TemporalSpringbootSamplesApplication.class, args).start(); + } +} diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java new file mode 100644 index 000000000..d727696f0 --- /dev/null +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello; + +import io.temporal.activity.ActivityInterface; +import io.temporal.samples.springboot.hello.model.Person; + +@ActivityInterface +public interface HelloActivity { + String hello(Person person); +} diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java new file mode 100644 index 000000000..6dd3a39fe --- /dev/null +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello; + +import io.temporal.samples.springboot.hello.model.Person; +import io.temporal.spring.boot.ActivityImpl; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@ActivityImpl(taskQueues = "HelloSampleTaskQueue") +public class HelloActivityImpl implements HelloActivity { + @Value("${samples.data.language}") + private String language; + + @Override + public String hello(Person person) { + String greeting = language.equals("spanish") ? "Hola " : "Hello "; + return greeting + person.getFirstName() + " " + person.getLastName() + "!"; + } +} diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java new file mode 100644 index 000000000..fd1675623 --- /dev/null +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello; + +import io.temporal.samples.springboot.hello.model.Person; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloWorkflow { + @WorkflowMethod + String sayHello(Person person); +} diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java new file mode 100644 index 000000000..05336a9f3 --- /dev/null +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello; + +import io.temporal.activity.ActivityOptions; +import io.temporal.samples.springboot.hello.model.Person; +import io.temporal.spring.boot.WorkflowImpl; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +@WorkflowImpl(taskQueues = "HelloSampleTaskQueue") +public class HelloWorkflowImpl implements HelloWorkflow { + + private HelloActivity activity = + Workflow.newActivityStub( + HelloActivity.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String sayHello(Person person) { + return activity.hello(person); + } +} diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/README.md b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/README.md new file mode 100644 index 000000000..9a878a412 --- /dev/null +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/README.md @@ -0,0 +1,16 @@ +# SpringBoot Hello Sample + +1. Start SpringBoot from main samples repo directory: + + ./gradlew :springboot-basic:bootRun + +2. In your browser navigate to: + + http://localhost:3030/hello + +Enter in first and last name in the form then click on Run Workflow +to start workflow execution. Page will be updated to show the workflow +execution results (the greeting). + +You can try changing the language setting in [application.yaml](../../../../../../resources/application.yaml) file +from "english" to "spanish" to get the greeting result in Spanish. \ No newline at end of file diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java new file mode 100644 index 000000000..c71862b23 --- /dev/null +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.hello.model; + +public class Person { + private String firstName; + private String lastName; + + public Person() {} + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/springboot-basic/src/main/resources/application-tc.yaml b/springboot-basic/src/main/resources/application-tc.yaml new file mode 100644 index 000000000..041d67e06 --- /dev/null +++ b/springboot-basic/src/main/resources/application-tc.yaml @@ -0,0 +1,9 @@ +spring.temporal: + namespace: # https://docs.temporal.io/cloud/#temporal-cloud-namespace-id + connection: + target: .tmprl.cloud:7233 + mtls: + key-file: /path/to/key.key + cert-chain-file: /path/to/cert.pem + +# more configuration options https://github.com/temporalio/sdk-java/tree/master/temporal-spring-boot-autoconfigure-alpha#mtls \ No newline at end of file diff --git a/springboot-basic/src/main/resources/application.yaml b/springboot-basic/src/main/resources/application.yaml new file mode 100644 index 000000000..7c0e33ab0 --- /dev/null +++ b/springboot-basic/src/main/resources/application.yaml @@ -0,0 +1,18 @@ +server: + port: 3030 +spring: + main: + allow-bean-definition-overriding: true + application: + name: temporal-samples + # temporal specific configs + temporal: + namespace: default + connection: + target: 127.0.0.1:7233 + workersAutoDiscovery: + packages: io.temporal.samples.springboot +# specific for samples +samples: + data: + language: english diff --git a/springboot-basic/src/main/resources/static/js/jquery.sse.js b/springboot-basic/src/main/resources/static/js/jquery.sse.js new file mode 100644 index 000000000..67bd52ecd --- /dev/null +++ b/springboot-basic/src/main/resources/static/js/jquery.sse.js @@ -0,0 +1,199 @@ +/* + * jQuery Plugin for Server-Sent Events (SSE) EventSource Polyfill v0.1.3 + * https://github.com/byjg/jquery-sse + * + * This document is licensed as free software under the terms of the + * MIT License: http://www.opensource.org/licenses/mit-license.php + * + * Copyright (c) 2015 by JG (JoΓ£o Gilberto MagalhΓ£es). + */ +(function ($) { + $.extend({ + SSE: function (url, customSettings) { + var sse = {instance: null, type: null}; + + var settings = { + onOpen: function (e) { + }, + onEnd: function (e) { + }, + onError: function (e) { + }, + onMessage: function (e) { + }, + options: {}, + headers: {}, + events: {} + }; + + $.extend(settings, customSettings); + + sse._url = url; + sse._settings = settings; + + // Start the proper EventSource object or Ajax fallback + sse._start = sse.start; + sse.start = function () { + if (this.instance) { + return false; + } + + if (!window.EventSource || this._settings.options.forceAjax || (Object.keys(this._settings.headers).length > 0)) { + createAjax(this); + } else { + createEventSource(this); + } + + return true; + }; + + // Stop the proper object + sse.stop = function () { + if (!this.instance) { + return false; + } + + if (!window.EventSource || this._settings.options.forceAjax || (Object.keys(this._settings.headers).length > 0)) { + // Nothing to do; + } else { + this.instance.close(); + } + this._settings.onEnd(); + + this.instance = null; + this.type = null; + + return true; + + }; + + return sse; + + } + }); + + + // Private Method for Handle EventSource object + function createEventSource(me) { + me.type = 'event'; + me.instance = new EventSource(me._url); + me.instance.successCount = 0; + + me.instance.onmessage = me._settings.onMessage; + me.instance.onopen = function (e) { + if (me.instance.successCount++ === 0) { + me._settings.onOpen(e); + } + }; + me.instance.onerror = function (e) { + if (e.target.readyState === EventSource.CLOSED) { + me._settings.onError(e); + } + }; + + for (var key in me._settings.events) { + me.instance.addEventListener(key, me._settings.events[key], false); + } + } + + // Handle the Ajax instance (fallback) + function createAjax(me) { + me.type = 'ajax'; + me.instance = {successCount: 0, id: null, retry: 3000, data: "", event: ""}; + runAjax(me); + } + + // Handle the continous Ajax request (fallback) + function runAjax(me) { + if (!me.instance) { + return; + } + + var headers = {'Last-Event-ID': me.instance.id}; + + $.extend(headers, me._settings.headers); + + $.ajax({ + url: me._url, + method: 'GET', + headers: headers, + success: function (receivedData, status, info) { + if (!me.instance) { + return; + } + + if (me.instance.successCount++ === 0) { + me._settings.onOpen(); + } + + var lines = receivedData.split("\n"); + + // Process the return to generate a compatible SSE response + me.instance.data = ""; + var countBreakLine = 0; + for (var key in lines) { + var separatorPos = lines[key].indexOf(":"); + var item = [ + lines[key].substr(0, separatorPos), + lines[key].substr(separatorPos + 1) + ]; + switch (item[0]) { + // If the first part is empty, needed to check another sequence + case "": + if (!item[1] && countBreakLine++ === 1) { // Avoid comments! + eventMessage = { + data: me.instance.data, + lastEventId: me.instance.id, + origin: 'http://' + info.getResponseHeader('Host'), + returnValue: true + }; + + // If there are a custom event then call it + if (me.instance.event && me._settings.events[me.instance.event]) { + me._settings.events[me.instance.event](eventMessage); + } else { + me._settings.onMessage(eventMessage); + } + me.instance.data = ""; + me.instance.event = ""; + countBreakLine = 0; + } + break; + + // Define the new retry object; + case "retry": + countBreakLine = 0; + me.instance.retry = parseInt(item[1].trim()); + break; + + // Define the new ID + case "id": + countBreakLine = 0; + me.instance.id = item[1].trim(); + break; + + // Define a custom event + case "event": + countBreakLine = 0; + me.instance.event = item[1].trim(); + break; + + // Define the data to be processed. + case "data": + countBreakLine = 0; + me.instance.data += (me.instance.data !== "" ? "\n" : "") + item[1].trim(); + break; + + default: + countBreakLine = 0; + } + } + setTimeout(function () { + runAjax(me); + }, me.instance.retry); + }, + error: me._settings.onError + }); + } + +})(jQuery); diff --git a/springboot-basic/src/main/resources/static/js/samplessse.js b/springboot-basic/src/main/resources/static/js/samplessse.js new file mode 100644 index 000000000..79dc90371 --- /dev/null +++ b/springboot-basic/src/main/resources/static/js/samplessse.js @@ -0,0 +1,18 @@ +$( document ).ready(function() { + + var sse = $.SSE('/kafka-messages', { + onMessage: function(e){ + console.log(e); + $('#kafka-messages tr:last').after(''+e.data+''); + }, + onError: function(e){ + sse.stop(); + console.log("Could not connect..Stopping SSE"); + }, + onEnd: function(e){ + console.log("End"); + } + }); + sse.start(); + +}); \ No newline at end of file diff --git a/springboot-basic/src/main/resources/templates/fragments.html b/springboot-basic/src/main/resources/templates/fragments.html new file mode 100644 index 000000000..29b0a1ff1 --- /dev/null +++ b/springboot-basic/src/main/resources/templates/fragments.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + +

+ + \ No newline at end of file diff --git a/springboot-basic/src/main/resources/templates/hello.html b/springboot-basic/src/main/resources/templates/hello.html new file mode 100644 index 000000000..8bf6b7f0c --- /dev/null +++ b/springboot-basic/src/main/resources/templates/hello.html @@ -0,0 +1,56 @@ + + + + +
+
+
+

Temporal Java SDK Samples

+
This is a simple greeting example. Enter persons first and last name then submit form to start + workflow execution. Results will be updated on the page.
+
+


+
Say hello to:
+
+

First Name:

+

Last Name:

+

+ +

+
+
+
+
+
Workflow result:
+
+
+
+
+
+ +
+ + \ No newline at end of file diff --git a/springboot-basic/src/main/resources/templates/index.html b/springboot-basic/src/main/resources/templates/index.html new file mode 100644 index 000000000..7c14833e3 --- /dev/null +++ b/springboot-basic/src/main/resources/templates/index.html @@ -0,0 +1,17 @@ + + + + +
+
+
+
Temporal Java SDK Samples
+

Click on sample link to run it.

+
+ Say Hello +
+
+
+
+ + \ No newline at end of file diff --git a/springboot-basic/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java b/springboot-basic/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java new file mode 100644 index 000000000..1aab3fdc0 --- /dev/null +++ b/springboot-basic/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.springboot.hello.HelloWorkflow; +import io.temporal.samples.springboot.hello.model.Person; +import io.temporal.testing.TestWorkflowEnvironment; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.util.Assert; + +@SpringBootTest(classes = HelloSampleTest.Configuration.class) +@ActiveProfiles("test") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@DirtiesContext +public class HelloSampleTest { + + @Autowired ConfigurableApplicationContext applicationContext; + + @Autowired TestWorkflowEnvironment testWorkflowEnvironment; + + @Autowired WorkflowClient workflowClient; + + @BeforeEach + void setUp() { + applicationContext.start(); + } + + @Test + public void testHello() { + HelloWorkflow workflow = + workflowClient.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("HelloSampleTaskQueue") + .setWorkflowId("HelloSampleTest") + .build()); + String result = workflow.sayHello(new Person("Temporal", "User")); + Assert.notNull(result, "Greeting should not be null"); + Assert.isTrue(result.equals("Hello Temporal User!"), "Invalid result"); + } + + @ComponentScan + public static class Configuration {} +} diff --git a/springboot-basic/src/test/resources/application.yaml b/springboot-basic/src/test/resources/application.yaml new file mode 100644 index 000000000..26771c7cc --- /dev/null +++ b/springboot-basic/src/test/resources/application.yaml @@ -0,0 +1,21 @@ +server: + port: 3030 +spring: + main: + allow-bean-definition-overriding: true + application: + name: temporal-samples + # temporal specific configs + temporal: + connection: + target: 127.0.0.1:7233 + target.namespace: default + workersAutoDiscovery: + packages: io.temporal.samples.springboot + # enable test server for testing + test-server: + enabled: true +# specific for samples +samples: + data: + language: english diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/README.md b/springboot/src/main/java/io/temporal/samples/springboot/customize/README.md index c3d412104..12d803f43 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/customize/README.md +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/README.md @@ -17,7 +17,7 @@ as local activity which should succeed. ## How to run 1. Start SpringBoot from main samples repo directory: - ./gradlew bootRun + ./gradlew :springboot:bootRun 2. In your browser navigate to: diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md b/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md index 6c34c9445..98dfda78a 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/README.md @@ -2,7 +2,7 @@ 1. Start SpringBoot from main samples repo directory: - ./gradlew bootRun + ./gradlew :springboot:bootRun 2. In your browser navigate to: diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/README.md b/springboot/src/main/java/io/temporal/samples/springboot/kafka/README.md index 1c9dc8c71..56c009287 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/README.md +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/README.md @@ -2,7 +2,7 @@ 1. Start SpringBoot from main samples repo directory: - ./gradlew bootRun + ./gradlew :springboot:bootRun 2. In your browser navigate to: diff --git a/springboot/src/main/java/io/temporal/samples/springboot/metrics/README.md b/springboot/src/main/java/io/temporal/samples/springboot/metrics/README.md index 95a518523..7b5f4b48a 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/metrics/README.md +++ b/springboot/src/main/java/io/temporal/samples/springboot/metrics/README.md @@ -2,7 +2,7 @@ 1. Start SpringBoot from main samples repo directory: - ./gradlew bootRun + ./gradlew :springboot:bootRun 2. In your browser navigate to: diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/README.md b/springboot/src/main/java/io/temporal/samples/springboot/update/README.md index fdeaba18a..4ba2989b3 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/README.md +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/README.md @@ -2,7 +2,7 @@ 1. Start SpringBoot from main samples repo directory: - ./gradlew bootRun + ./gradlew :springboot:bootRun 2. In your browser navigate to: From 381ec1697b0871626099b1c358c61a4e2f31a94b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 14:58:12 -0500 Subject: [PATCH 137/240] Bump javaSDKVersion from 1.22.2 to 1.22.3 (#559) Bumps `javaSDKVersion` from 1.22.2 to 1.22.3. Updates `io.temporal:temporal-sdk` from 1.22.2 to 1.22.3 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.22.2...v1.22.3) Updates `io.temporal:temporal-opentracing` from 1.22.2 to 1.22.3 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.22.2...v1.22.3) Updates `io.temporal:temporal-testing` from 1.22.2 to 1.22.3 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.22.2...v1.22.3) Updates `io.temporal:temporal-spring-boot-starter-alpha` from 1.22.2 to 1.22.3 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.22.2...v1.22.3) --- updated-dependencies: - dependency-name: io.temporal:temporal-sdk dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-opentracing dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-testing dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-spring-boot-starter-alpha dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 663a8f2dc..991cbb7c3 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.22.2' + javaSDKVersion = '1.22.3' jarVersion = '1.0.0' } From e2efb7f6b5f8adfd17772fbd66fc08b4a56860c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 14:58:37 -0500 Subject: [PATCH 138/240] Bump ch.qos.logback:logback-classic from 1.4.12 to 1.4.14 (#560) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.12 to 1.4.14. - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.12...v_1.4.14) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 998aa476c..f80a38d7c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.12' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.14' implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) From 308b01bdeb8e0778562de4c1c528ed3d72adde8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 14:59:04 -0500 Subject: [PATCH 139/240] Bump io.serverlessworkflow:serverlessworkflow-spi (#561) Bumps [io.serverlessworkflow:serverlessworkflow-spi](https://github.com/serverlessworkflow/sdk-java) from 4.0.4.Final to 4.0.5.Final. - [Release notes](https://github.com/serverlessworkflow/sdk-java/releases) - [Commits](https://github.com/serverlessworkflow/sdk-java/compare/4.0.4.Final...4.0.5.Final) --- updated-dependencies: - dependency-name: io.serverlessworkflow:serverlessworkflow-spi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index f80a38d7c..97350f88d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -29,7 +29,7 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.4.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.4.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.4.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.4.Final' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' From 2ccf4a6dea639bc70023b0c89932120ee744aa6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:25:04 -0500 Subject: [PATCH 140/240] Bump io.serverlessworkflow:serverlessworkflow-util (#563) Bumps io.serverlessworkflow:serverlessworkflow-util from 4.0.4.Final to 4.0.5.Final. --- updated-dependencies: - dependency-name: io.serverlessworkflow:serverlessworkflow-util dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 97350f88d..c9487ebb2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -29,8 +29,8 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.4.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.4.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.5.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.4.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.4.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.5.Final' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' // we don't update it to 2.1.0 because 2.1.0 requires Java 11 From 3b6a8775c37cc1323efb2a0a2add3d9c277d6ed7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:25:27 -0500 Subject: [PATCH 141/240] Bump com.fasterxml.jackson:jackson-bom from 2.15.3 to 2.16.1 (#566) Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.15.3 to 2.16.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.15.3...jackson-bom-2.16.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index c9487ebb2..d772c24c1 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:$javaSDKVersion") // Needed for SDK related functionality - implementation(platform("com.fasterxml.jackson:jackson-bom:2.15.3")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.16.1")) implementation "com.fasterxml.jackson.core:jackson-databind" implementation "com.fasterxml.jackson.core:jackson-core" From 7820cbac74c92b9a96a14cdb562a5f9f7597d5e0 Mon Sep 17 00:00:00 2001 From: "mend-for-github-com[bot]" <50673670+mend-for-github-com[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:25:52 -0500 Subject: [PATCH 142/240] Update dependency com.jayway.jsonpath:json-path to v2.9.0 (#572) Co-authored-by: mend-for-github-com[bot] <50673670+mend-for-github-com[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index d772c24c1..f29d6a951 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -12,7 +12,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.14' - implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0' + implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) implementation "io.opentelemetry:opentelemetry-sdk" From dfb685cedbab42f05d5cc21b7c17c18d10c6f15c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:26:15 -0500 Subject: [PATCH 143/240] Bump gradle/wrapper-validation-action from 1 to 2 (#575) Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from 1 to 2. - [Release notes](https://github.com/gradle/wrapper-validation-action/releases) - [Commits](https://github.com/gradle/wrapper-validation-action/compare/v1...v2) --- updated-dependencies: - dependency-name: gradle/wrapper-validation-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gradle-wrapper-validation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index a8195158c..f5ccf04c7 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -7,4 +7,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v1 + - uses: gradle/wrapper-validation-action@v2 From 33ac24ccdf0f34fc34e55f006608e3c0d652c088 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Thu, 15 Feb 2024 18:00:37 -0500 Subject: [PATCH 144/240] Timer based signal processing sample (#580) * timer based signal processing sample [cont] Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * added test and update to readme Signed-off-by: Tihomir Surdilovic * updated per comments Signed-off-by: Tihomir Surdilovic * removed unneeded catch Signed-off-by: Tihomir Surdilovic * adding processing dummy activity Signed-off-by: Tihomir Surdilovic * removed unneeded processedLast boolean Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 1 + .../samples/hello/HelloSignalWithTimer.java | 181 ++++++++++++++++++ .../java/io/temporal/samples/hello/README.md | 1 + .../hello/HelloSignalWithTimerTest.java | 78 ++++++++ 4 files changed, 261 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloSignalWithTimerTest.java diff --git a/README.md b/README.md index f3ccce048..c63280cd8 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloSideEffect**](/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java)**: Demonstrates how to implement a Side Effect. - [**HelloUpdate**](/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java): Demonstrates how to create and interact with an Update. - [**HelloDelayedStart**](/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java): Demonstrates how to use delayed start config option when starting a Workflow Executions. + - [**HelloSignalWithTimer**](/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java): Demonstrates how to use collect signals for certain amount of time and then process last one. #### Scenario-based samples diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java new file mode 100644 index 000000000..804034ffa --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityOptions; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.CanceledFailure; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.*; +import java.time.Duration; +import org.slf4j.Logger; + +/** + * Sample Temporal workflow that shows receiving signals for a specific time period and then process + * last one received and continue as new. + */ +public class HelloSignalWithTimer { + static final String TASK_QUEUE = "HelloSignalWithTimerTaskQueue"; + static final String WORKFLOW_ID = "HelloSignalWithTimerWorkflow"; + + @WorkflowInterface + public interface SignalWithTimerWorkflow { + @WorkflowMethod + void execute(); + + @SignalMethod + void newValue(String value); + + @SignalMethod + void exit(); + } + + @ActivityInterface + public interface ValueProcessingActivities { + void processValue(String value); + } + + public static class SignalWithTimerWorkflowImpl implements SignalWithTimerWorkflow { + + private Logger logger = Workflow.getLogger(SignalWithTimerWorkflowImpl.class); + private String lastValue = ""; + private CancellationScope timerScope; + private boolean exit = false; + + private final ValueProcessingActivities activities = + Workflow.newActivityStub( + ValueProcessingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public void execute() { + // Just in case if exit signal is sent as soon as execution is started + if (exit) { + return; + } + // Start timer in cancellation scope so we can cancel it on exit signal received + timerScope = + Workflow.newCancellationScope( + () -> { + try { + // You can add a signal handler that updates the sleep duration + // As it may change via business logic over time + // For sample we just hard code it to 5 seconds + Workflow.newTimer(Duration.ofSeconds(5)).get(); + } catch (CanceledFailure e) { + // Exit signal is received causing cancellation of timer scope and timer + // For sample we just log it, you can handle it if needed + logger.info("Timer canceled via exit signal"); + } + }); + timerScope.run(); + + // Process last received signal and either exit or ContinueAsNew depending on if we got + // Exit signal or not + activities.processValue(lastValue); + + if (exit) { + return; + } else { + SignalWithTimerWorkflow nextRun = + Workflow.newContinueAsNewStub(SignalWithTimerWorkflow.class); + nextRun.execute(); + } + } + + @Override + public void newValue(String value) { + // Note that we can receive a signal at the same time workflow is trying to complete or + // ContinueAsNew. This would cause workflow task failure with UnhandledCommand + // in order to deliver this signal to our execution. + // You can choose what to do in this case depending on business logic. + // For this sample we just ignore it, alternative could be to process it or carry it over + // to the continued execution if needed. + lastValue = value; + } + + @Override + public void exit() { + if (timerScope != null) { + timerScope.cancel("exit received"); + } + this.exit = true; + } + } + + static class ValueProcessingActivitiesImpl implements ValueProcessingActivities { + @Override + public void processValue(String value) { + // Here you would access downstream services to process the value + // Dummy impl for sample, do nothing + System.out.println("Processing value: " + value); + } + } + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(TASK_QUEUE); + worker.registerWorkflowImplementationTypes(SignalWithTimerWorkflowImpl.class); + worker.registerActivitiesImplementations(new ValueProcessingActivitiesImpl()); + + factory.start(); + + SignalWithTimerWorkflow workflow = + client.newWorkflowStub( + SignalWithTimerWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + // Start execution, this unblocks when its created by service + WorkflowClient.start(workflow::execute); + + // Send signals 2s apart 12 times (to simulate cancellation on last ContinueAsNew) + for (int i = 0; i < 12; i++) { + workflow.newValue("Value " + i); + sleep(2); + } + sleep(1); + // Send exit signal + workflow.exit(); + + // Wait for execution to complete after receiving exit signal. + // This should unblock pretty much immediately + WorkflowStub.fromTyped(workflow).getResult(Void.class); + + System.exit(0); + } + + private static void sleep(int seconds) { + try { + Thread.sleep(seconds * 1000L); + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + } + } +} diff --git a/core/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md index 09a083a7d..746d89c32 100644 --- a/core/src/main/java/io/temporal/samples/hello/README.md +++ b/core/src/main/java/io/temporal/samples/hello/README.md @@ -31,4 +31,5 @@ To run each hello world sample, use one of the following commands: ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloTypedSearchAttributes ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSideEffect ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloUpdate +./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignalWithTimer ``` diff --git a/core/src/test/java/io/temporal/samples/hello/HelloSignalWithTimerTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSignalWithTimerTest.java new file mode 100644 index 000000000..c65fec165 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloSignalWithTimerTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.WorkflowExecutionStatus; +import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionRequest; +import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionResponse; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class HelloSignalWithTimerTest { + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(HelloSignalWithTimer.SignalWithTimerWorkflowImpl.class) + .setActivityImplementations(new HelloSignalWithTimer.ValueProcessingActivitiesImpl()) + .build(); + + private static final String WORKFLOW_ID = "SignalWithTimerTestWorkflow"; + + @Test + public void testSignalWithTimer() { + HelloSignalWithTimer.SignalWithTimerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloSignalWithTimer.SignalWithTimerWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(WORKFLOW_ID) + .build()); + + WorkflowClient.start(workflow::execute); + workflow.newValue("1"); + workflow.newValue("2"); + workflow.exit(); + + WorkflowStub.fromTyped(workflow).getResult(Void.class); + + DescribeWorkflowExecutionResponse res = + testWorkflowRule + .getWorkflowClient() + .getWorkflowServiceStubs() + .blockingStub() + .describeWorkflowExecution( + DescribeWorkflowExecutionRequest.newBuilder() + .setNamespace(testWorkflowRule.getTestEnvironment().getNamespace()) + .setExecution(WorkflowExecution.newBuilder().setWorkflowId(WORKFLOW_ID).build()) + .build()); + + Assert.assertEquals( + res.getWorkflowExecutionInfo().getStatus(), + WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_COMPLETED); + } +} From 09513565222214019e200c925d8d51b2758ef677 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 11:18:06 -0500 Subject: [PATCH 145/240] Bump io.serverlessworkflow:serverlessworkflow-spi (#585) Bumps [io.serverlessworkflow:serverlessworkflow-spi](https://github.com/serverlessworkflow/sdk-java) from 4.0.4.Final to 4.0.5.Final. - [Release notes](https://github.com/serverlessworkflow/sdk-java/releases) - [Commits](https://github.com/serverlessworkflow/sdk-java/compare/4.0.4.Final...4.0.5.Final) --- updated-dependencies: - dependency-name: io.serverlessworkflow:serverlessworkflow-spi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index f29d6a951..47cd4fdac 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -29,7 +29,7 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.4.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.4.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.4.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.5.Final' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' From 42823de239e39122aca74463af5fe2db0027adc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 12:25:02 -0500 Subject: [PATCH 146/240] Bump io.serverlessworkflow:serverlessworkflow-validation (#586) Bumps [io.serverlessworkflow:serverlessworkflow-validation](https://github.com/serverlessworkflow/sdk-java) from 4.0.4.Final to 4.0.5.Final. - [Release notes](https://github.com/serverlessworkflow/sdk-java/releases) - [Commits](https://github.com/serverlessworkflow/sdk-java/compare/4.0.4.Final...4.0.5.Final) --- updated-dependencies: - dependency-name: io.serverlessworkflow:serverlessworkflow-validation dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tihomir Surdilovic --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 47cd4fdac..84f22201b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -27,8 +27,8 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.4.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.4.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.5.Final' + implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.5.Final' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' From 124842b21f1f4de2f45611a7e8a868c8fab0c197 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 12:25:26 -0500 Subject: [PATCH 147/240] Bump ch.qos.logback:logback-classic from 1.4.14 to 1.5.0 (#584) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.14 to 1.5.0. - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.14...v_1.5.0) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 84f22201b..0f4c78bfe 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.14' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.0' implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) From aac230134d9536cd97e60e9831d147b76d0b697d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 12:25:53 -0500 Subject: [PATCH 148/240] Bump com.google.errorprone:error_prone_core from 2.22.0 to 2.25.0 (#583) Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.22.0 to 2.25.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.22.0...v2.25.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- springboot-basic/build.gradle | 4 ++-- springboot/build.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 0f4c78bfe..578fea6a7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -46,7 +46,7 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.23.0') + errorprone('com.google.errorprone:error_prone_core:2.25.0') } } diff --git a/springboot-basic/build.gradle b/springboot-basic/build.gradle index 9d621e005..6a2c9c953 100644 --- a/springboot-basic/build.gradle +++ b/springboot-basic/build.gradle @@ -10,9 +10,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.22.0') + errorprone('com.google.errorprone:error_prone_core:2.25.0') } else { - errorprone('com.google.errorprone:error_prone_core:2.22.0') + errorprone('com.google.errorprone:error_prone_core:2.25.0') } } } diff --git a/springboot/build.gradle b/springboot/build.gradle index 569e1cc91..07aa84c18 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -14,7 +14,7 @@ dependencies { testImplementation "org.springframework.boot:spring-boot-starter-test" dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.23.0') + errorprone('com.google.errorprone:error_prone_core:2.25.0') } } From 15415ef95f162ed602737164828475d397bc433f Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Sun, 25 Feb 2024 21:56:44 -0500 Subject: [PATCH 149/240] SpringBoot - Apache Camel Sample (#581) Signed-off-by: Tihomir Surdilovic --- README.md | 2 +- build.gradle | 1 + springboot/build.gradle | 2 + .../samples/springboot/SamplesController.java | 8 +- .../samples/springboot/camel/CamelConfig.java | 55 +++++++++++ .../springboot/camel/CamelResource.java | 41 +++++++++ .../samples/springboot/camel/CamelRoutes.java | 51 ++++++++++ .../samples/springboot/camel/OfficeOrder.java | 92 +++++++++++++++++++ .../springboot/camel/OrderActivity.java | 28 ++++++ .../springboot/camel/OrderActivityImpl.java | 37 ++++++++ .../springboot/camel/OrderRepository.java | 26 ++++++ .../springboot/camel/OrderWorkflow.java | 30 ++++++ .../springboot/camel/OrderWorkflowImpl.java | 40 ++++++++ .../samples/springboot/camel/README.md | 12 +++ springboot/src/main/resources/data.sql | 12 ++- .../src/main/resources/templates/camel.html | 27 ++++++ .../src/main/resources/templates/index.html | 3 + .../samples/springboot/CamelSampleTest.java | 70 ++++++++++++++ 18 files changed, 534 insertions(+), 3 deletions(-) create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/CamelConfig.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/CamelResource.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/OfficeOrder.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivity.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/OrderRepository.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflow.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflowImpl.java create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/camel/README.md create mode 100644 springboot/src/main/resources/templates/camel.html create mode 100644 springboot/src/test/java/io/temporal/samples/springboot/CamelSampleTest.java diff --git a/README.md b/README.md index c63280cd8..f04500e19 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ More info on each sample: - [**Synchronous Update**](/springboot/src/main/java/io/temporal/samples/springboot/update): Learn how to use Synchronous Update feature with this purchase sample - [**Kafka Request / Reply**](/springboot/src/main/java/io/temporal/samples/springboot/kafka): Sample showing possible integration with event streaming platforms such as Kafka - [**Customize Options**](/springboot/src/main/java/io/temporal/samples/springboot/customize): Sample showing how to customize options such as WorkerOptions, WorkerFactoryOptions, etc (see options config [here](springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java)) - +- [**Apache Camel Route**](/springboot/src/main/java/io/temporal/samples/springboot/camel): Sample showing how to start Workflow execution from a Camel Route #### Temporal Cloud To run any of the SpringBoot samples in your Temporal Cloud namespace: diff --git a/build.gradle b/build.gradle index 991cbb7c3..6195b64f9 100644 --- a/build.gradle +++ b/build.gradle @@ -29,6 +29,7 @@ subprojects { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" javaSDKVersion = '1.22.3' + camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/springboot/build.gradle b/springboot/build.gradle index 07aa84c18..d9939248f 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -9,6 +9,8 @@ dependencies { // we set this as impl depends to use embedded kafka in samples not just tests implementation "org.springframework.kafka:spring-kafka-test" implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" + implementation "org.apache.camel.springboot:camel-spring-boot-starter:$camelVersion" + implementation "org.apache.camel.springboot:camel-servlet-starter:$camelVersion" runtimeOnly "io.micrometer:micrometer-registry-prometheus" runtimeOnly "com.h2database:h2" testImplementation "org.springframework.boot:spring-boot-starter-test" diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index 6d8540704..a9799d096 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -127,7 +127,7 @@ ResponseEntity purchase(@RequestBody Purchase purchase) { } @GetMapping("/kafka") - public String afka(Model model) { + public String kafka(Model model) { model.addAttribute("sample", "Kafka Request / Reply"); return "kafka"; } @@ -176,4 +176,10 @@ ResponseEntity customizeSample() { // bypass thymeleaf, don't return template name just result return new ResponseEntity<>("\"" + workflow.execute() + "\"", HttpStatus.OK); } + + @GetMapping("/camel") + public String camel(Model model) { + model.addAttribute("sample", "Camel Route"); + return "camel"; + } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelConfig.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelConfig.java new file mode 100644 index 000000000..febb78464 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelConfig.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import org.apache.camel.CamelContext; +import org.apache.camel.ConsumerTemplate; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.servlet.CamelHttpTransportServlet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration() +@Profile("!test") +public class CamelConfig { + @Autowired private CamelContext camelContext; + + @Bean + ServletRegistrationBean servletRegistrationBean() { + String contextPath = "/temporalapp"; + ServletRegistrationBean servlet = + new ServletRegistrationBean(new CamelHttpTransportServlet(), contextPath + "/*"); + servlet.setName("CamelServlet"); + return servlet; + } + + @Bean + ProducerTemplate producerTemplate() { + return camelContext.createProducerTemplate(); + } + + @Bean + ConsumerTemplate consumerTemplate() { + return camelContext.createConsumerTemplate(); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelResource.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelResource.java new file mode 100644 index 000000000..43cb142e6 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelResource.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import java.util.List; +import org.apache.camel.ProducerTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class CamelResource { + @Autowired private ProducerTemplate producerTemplate; + + @GetMapping("/orders") + @ResponseBody + public List getProductsByCategory() { + producerTemplate.start(); + List orders = producerTemplate.requestBody("direct:getOrders", null, List.class); + producerTemplate.stop(); + return orders; + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java new file mode 100644 index 000000000..42d964650 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import org.apache.camel.builder.RouteBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class CamelRoutes extends RouteBuilder { + + @Autowired private WorkflowClient workflowClient; + + @Override + public void configure() { + from("direct:getOrders") + .routeId("direct-getOrders") + .tracing() + .process( + exchange -> { + OrderWorkflow workflow = + workflowClient.newWorkflowStub( + OrderWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId("CamelSampleWorkflow") + .setTaskQueue("CamelSampleTaskQueue") + .build()); + exchange.getIn().setBody(workflow.start()); + }) + .end(); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OfficeOrder.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OfficeOrder.java new file mode 100644 index 000000000..82b998a21 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OfficeOrder.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import javax.persistence.*; + +@Entity +@Table(name = "officeorder") +public class OfficeOrder { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(nullable = false) + private String number; + + @Column(nullable = false) + private String desc; + + @Column(nullable = false) + private String date; + + @Column(nullable = false) + private double price; + + public OfficeOrder() {} + + public OfficeOrder(Integer id, String number, String desc, String date, double price) { + this.id = id; + this.number = number; + this.desc = desc; + this.date = date; + this.price = price; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getNumber() { + return number; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setNumber(String number) { + this.number = number; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivity.java new file mode 100644 index 000000000..f94d6ecf1 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivity.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import io.temporal.activity.ActivityInterface; +import java.util.List; + +@ActivityInterface +public interface OrderActivity { + List getOrders(); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java new file mode 100644 index 000000000..f87b5c5b4 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import io.temporal.spring.boot.ActivityImpl; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@ActivityImpl(taskQueues = "CamelSampleTaskQueue") +public class OrderActivityImpl implements OrderActivity { + + @Autowired OrderRepository repository; + + @Override + public List getOrders() { + return repository.findAll(); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderRepository.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderRepository.java new file mode 100644 index 000000000..255955112 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface OrderRepository extends JpaRepository {} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflow.java new file mode 100644 index 000000000..067d92bcf --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflow.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.util.List; + +@WorkflowInterface +public interface OrderWorkflow { + @WorkflowMethod + public List start(); +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflowImpl.java new file mode 100644 index 000000000..60a129e3e --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflowImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.camel; + +import io.temporal.activity.ActivityOptions; +import io.temporal.spring.boot.WorkflowImpl; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.List; + +@WorkflowImpl(taskQueues = "CamelSampleTaskQueue") +public class OrderWorkflowImpl implements OrderWorkflow { + + private OrderActivity activity = + Workflow.newActivityStub( + OrderActivity.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public List start() { + return activity.getOrders(); + } +} diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/README.md b/springboot/src/main/java/io/temporal/samples/springboot/camel/README.md new file mode 100644 index 000000000..f2d374dc5 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/README.md @@ -0,0 +1,12 @@ +# SpringBoot Camel Sample + +1. Start SpringBoot from main samples repo directory: + + ./gradlew :springboot:bootRun + +2. In your browser navigate to: + + http://localhost:3030/orders + +This sample starts an Apache Camel route which runs our orders Workflow. +Results of the workflow are returned by the Camel route \ No newline at end of file diff --git a/springboot/src/main/resources/data.sql b/springboot/src/main/resources/data.sql index cd2d206c6..607e95aed 100644 --- a/springboot/src/main/resources/data.sql +++ b/springboot/src/main/resources/data.sql @@ -2,4 +2,14 @@ INSERT INTO product(name, code, description, price, stock) VALUES ('Zoom U-Tale INSERT INTO product(name, code, description, price, stock) VALUES ('Yamamoto Baits 5" Senko', 'w2', 'Yamamoto Baits 5" Senko has become a mainstay for bass throughout the United States.', 7, 15); INSERT INTO product(name, code, description, price, stock) VALUES ('Rapala Original Floating Minnow', 'w3', 'The Rapala Original Floating Minnow is the lure that started it all and is still one of the most popular lures around.', 10, 10); INSERT INTO product(name, code, description, price, stock) VALUES ('Z-Man Jackhammer', 'w4', 'Exclusive patented ChatterBait bladed swim jig design and stainless hex-shaped ChatterBlade.', 18, 10); -INSERT INTO product(name, code, description, price, stock) VALUES ('Roboworm Straight Tail Worm Bait', 'w5', 'Roboworms are the most consistant poured baits on the market.', 9, 30); \ No newline at end of file +INSERT INTO product(name, code, description, price, stock) VALUES ('Roboworm Straight Tail Worm Bait', 'w5', 'Roboworms are the most consistant poured baits on the market.', 9, 30); + +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR1', '1/02/2004', 'Office Chair', 120); +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR2', '1/05/2004', 'Office Desk', 200); +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR3', '1/05/2004', 'Computer Mouse', 30); +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR4', '1/08/2004', 'Mouse Pad', 19); +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR5', '1/10/2004', 'Office Sofa', 170); +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR6', '1/12/2004', 'MacBook Air', 980); +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR7', '1/12/2004', 'Pens', 9); +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR8', '1/12/2004', 'Printer Paper', 22); +INSERT INTO officeorder(number, date, desc, price) VALUES ('OR9', '1/15/2004', 'Printer Cartridge', 110); \ No newline at end of file diff --git a/springboot/src/main/resources/templates/camel.html b/springboot/src/main/resources/templates/camel.html new file mode 100644 index 000000000..4c099ca50 --- /dev/null +++ b/springboot/src/main/resources/templates/camel.html @@ -0,0 +1,27 @@ + + + + +
+
+
+

Temporal Java SDK Samples

+
This sample shows how to start Workflow execution from an Apache Camel Route
+


+
+

Apache Camel is an integration framework + with a large number of out-of box integrations with many different apis. + In this sample we show how to integrate Temporal as part of a Camel Route which define steps + of messages from its source to destination. It allows you to bring numerous + advantages of Temporal such as high reliability and fault tolerance into your existing Camel applications. +

+

To run the sample navigate to localhost:3030/orders +
This endpoint starts a Camel Route which in turn starts our Workflow executipn and delivers results. +

+
+
+
+
+
+ + \ No newline at end of file diff --git a/springboot/src/main/resources/templates/index.html b/springboot/src/main/resources/templates/index.html index 6d0748021..34df6ec12 100644 --- a/springboot/src/main/resources/templates/index.html +++ b/springboot/src/main/resources/templates/index.html @@ -22,6 +22,9 @@
Temporal Java SDK Samples
+ diff --git a/springboot/src/test/java/io/temporal/samples/springboot/CamelSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/CamelSampleTest.java new file mode 100644 index 000000000..d751bc426 --- /dev/null +++ b/springboot/src/test/java/io/temporal/samples/springboot/CamelSampleTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.springboot.camel.OfficeOrder; +import io.temporal.samples.springboot.camel.OrderWorkflow; +import io.temporal.testing.TestWorkflowEnvironment; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.util.Assert; + +@SpringBootTest(classes = HelloSampleTest.Configuration.class) +@ActiveProfiles("test") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +// set this to omit setting up embedded kafka +@EnableAutoConfiguration(exclude = {KafkaAutoConfiguration.class}) +public class CamelSampleTest { + + @Autowired ConfigurableApplicationContext applicationContext; + + @Autowired TestWorkflowEnvironment testWorkflowEnvironment; + + @Autowired WorkflowClient workflowClient; + + @BeforeEach + void setUp() { + applicationContext.start(); + } + + @Test + public void testOrdersWorkflow() { + OrderWorkflow workflow = + workflowClient.newWorkflowStub( + OrderWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("CamelSampleTaskQueue") + .setWorkflowId("CamelSampleWorkflow") + .build()); + List result = workflow.start(); + Assert.notNull(result, "Result should not be null"); + Assert.isTrue(result.size() == 9, "Invalid result"); + } +} From fc82cf0f119a6d8efbf037be0d90a82cf84656e8 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Sun, 10 Mar 2024 20:04:40 -0700 Subject: [PATCH 150/240] Update Java SDK to v1.23.0 (#596) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6195b64f9..3e859f84a 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.22.3' + javaSDKVersion = '1.23.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } From 1da87b9660adc2efc77ac2a82007363617d3903a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 23:17:26 -0400 Subject: [PATCH 151/240] Bump org.junit:junit-bom from 5.10.1 to 5.10.2 (#588) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.10.1 to 5.10.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.1...r5.10.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 578fea6a7..3aa633ae6 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -39,7 +39,7 @@ dependencies { testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:5.8.0" - testImplementation(platform("org.junit:junit-bom:5.10.1")) + testImplementation(platform("org.junit:junit-bom:5.10.2")) testImplementation "org.junit.jupiter:junit-jupiter-api" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" testRuntimeOnly "org.junit.vintage:junit-vintage-engine" From e103268577a9ef4e1f5ae7530f9e4f8d78ff679a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 23:18:12 -0400 Subject: [PATCH 152/240] Bump net.thisptr:jackson-jq (#590) Bumps [net.thisptr:jackson-jq](https://github.com/eiiches/jackson-jq) from 1.0.0-preview.20230409 to 1.0.0-preview.20240207. - [Release notes](https://github.com/eiiches/jackson-jq/releases) - [Commits](https://github.com/eiiches/jackson-jq/compare/1.0.0-preview.20230409...1.0.0-preview.20240207) --- updated-dependencies: - dependency-name: net.thisptr:jackson-jq dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 3aa633ae6..f9c301296 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -31,7 +31,7 @@ dependencies { implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.5.Final' - implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20230409' + implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20240207' // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' From 30c03550420fe596dc0065d2d17e05bc2003dbec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 23:18:36 -0400 Subject: [PATCH 153/240] Bump com.diffplug.spotless from 6.22.0 to 6.25.0 (#592) Bumps com.diffplug.spotless from 6.22.0 to 6.25.0. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3e859f84a..16e719fd2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "3.1.0" - id 'com.diffplug.spotless' version '6.22.0' apply false + id 'com.diffplug.spotless' version '6.25.0' apply false id "org.springframework.boot" version "${springBootPluginVersion}" } From 2091ca1fb7e281acb5027b6d373a9a8a84a95502 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:33:51 -0400 Subject: [PATCH 154/240] Bump org.mockito:mockito-core from 5.8.0 to 5.11.0 (#594) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.8.0 to 5.11.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.8.0...v5.11.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index f9c301296..b87060230 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation 'com.codingrodent:jackson-json-crypto:1.1.0' testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.8.0" + testImplementation "org.mockito:mockito-core:5.11.0" testImplementation(platform("org.junit:junit-bom:5.10.2")) testImplementation "org.junit.jupiter:junit-jupiter-api" From 27f84a6a4586226a459141654517a8f08f7e4038 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:35:09 -0400 Subject: [PATCH 155/240] Bump ch.qos.logback:logback-classic from 1.5.0 to 1.5.3 (#600) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.5.0 to 1.5.3. - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.0...v_1.5.3) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index b87060230..64d5d363a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.0' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.3' implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) From 854ece33e3f65f8772026312f613f2f7d4f9cf23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:35:30 -0400 Subject: [PATCH 156/240] Bump com.fasterxml.jackson:jackson-bom from 2.16.1 to 2.17.0 (#601) Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.16.1 to 2.17.0. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.16.1...jackson-bom-2.17.0) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 64d5d363a..9a584b659 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:$javaSDKVersion") // Needed for SDK related functionality - implementation(platform("com.fasterxml.jackson:jackson-bom:2.16.1")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.0")) implementation "com.fasterxml.jackson.core:jackson-databind" implementation "com.fasterxml.jackson.core:jackson-core" From 4058f18e499d01c0a0c9377520133ee58ae17019 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:35:52 -0400 Subject: [PATCH 157/240] Bump com.google.errorprone:error_prone_core from 2.25.0 to 2.26.1 (#602) Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.25.0 to 2.26.1. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.25.0...v2.26.1) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- springboot-basic/build.gradle | 4 ++-- springboot/build.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 9a584b659..68c005aae 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -46,7 +46,7 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.25.0') + errorprone('com.google.errorprone:error_prone_core:2.26.1') } } diff --git a/springboot-basic/build.gradle b/springboot-basic/build.gradle index 6a2c9c953..42b8637aa 100644 --- a/springboot-basic/build.gradle +++ b/springboot-basic/build.gradle @@ -10,9 +10,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.25.0') + errorprone('com.google.errorprone:error_prone_core:2.26.1') } else { - errorprone('com.google.errorprone:error_prone_core:2.25.0') + errorprone('com.google.errorprone:error_prone_core:2.26.1') } } } diff --git a/springboot/build.gradle b/springboot/build.gradle index d9939248f..7ae490cae 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation "org.springframework.boot:spring-boot-starter-test" dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.25.0') + errorprone('com.google.errorprone:error_prone_core:2.26.1') } } From 2964133f7b8171db0ea1ce9704ccc2e6f04e331a Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Wed, 3 Apr 2024 10:32:34 -0400 Subject: [PATCH 158/240] update sdk version to 1.23.1 (#608) Signed-off-by: Tihomir Surdilovic --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 16e719fd2..a31abc5ab 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.23.0' + javaSDKVersion = '1.23.1' camelVersion = '3.22.1' jarVersion = '1.0.0' } From d069d2bf7d66b20644989a8422160cc51241c490 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Wed, 3 Apr 2024 11:56:07 -0400 Subject: [PATCH 159/240] Add KeyWordList type to typed SA sample (#607) * Add KeyWordList type to typed SA sample Signed-off-by: Tihomir Surdilovic * formatting Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- .../hello/HelloTypedSearchAttributes.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java index 589778c19..df196d762 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java @@ -34,10 +34,24 @@ import java.time.Duration; import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.util.Arrays; +import java.util.List; +import java.util.StringJoiner; /** * Sample Temporal workflow that demonstrates setting up, updating, and retrieving workflow search * attributes using the typed search attributes API. + * + *

NOTE: you may need to add these custom search attributes yourself before running the sample. + * If you are using autosetup image for service, you will need to create the + * "CustomKeywordListField" search attribute with Temporal cli, for example: + * + *

temporal operator search-attribute create -name "CustomKeywordListField" -type "KeywordList" + * + *

If you run your test and don't have some custom SA defined that are used here you would see + * error like: INVALID_ARGUMENT: Namespace default has no mapping defined for search attribute + * CustomBoolField when trying to start the workflow execution. In that case use cli to add the + * needed search attribute with its needed type. */ public class HelloTypedSearchAttributes { @@ -50,6 +64,8 @@ public class HelloTypedSearchAttributes { // Define all our search attributes with appropriate types static final SearchAttributeKey CUSTOM_KEYWORD_SA = SearchAttributeKey.forKeyword("CustomKeywordField"); + static final SearchAttributeKey> CUSTOM_KEYWORD_LIST_SA = + SearchAttributeKey.forKeywordList("CustomKeywordListField"); static final SearchAttributeKey CUSTOM_LONG_SA = SearchAttributeKey.forLong("CustomIntField"); static final SearchAttributeKey CUSTOM_DOUBLE_SA = @@ -95,7 +111,7 @@ public interface GreetingWorkflow { @ActivityInterface public interface GreetingActivities { @ActivityMethod - String composeGreeting(String greeting, String name); + String composeGreeting(String greeting, List salutations, String name); } // Define the workflow implementation which implements our getGreeting workflow method. @@ -124,8 +140,9 @@ public String getGreeting(String name) { io.temporal.common.SearchAttributes searchAttributes = Workflow.getTypedSearchAttributes(); // Get a particular value out of the container using the typed key String greeting = searchAttributes.get(CUSTOM_KEYWORD_SA); + List salutations = searchAttributes.get(CUSTOM_KEYWORD_LIST_SA); // This is a blocking call that returns only after the activity has completed. - return activities.composeGreeting(greeting, name); + return activities.composeGreeting(greeting, salutations, name); } } @@ -135,8 +152,13 @@ public String getGreeting(String name) { */ static class GreetingActivitiesImpl implements GreetingActivities { @Override - public String composeGreeting(String greeting, String name) { - return greeting + " " + name + "!"; + public String composeGreeting(String greeting, List salutations, String name) { + StringJoiner greetingJoiner = new StringJoiner(" "); + greetingJoiner.add(greeting); + greetingJoiner.add(name); + salutations.forEach(s -> greetingJoiner.add(s)); + + return greetingJoiner.toString(); } } @@ -211,6 +233,7 @@ public static void main(String[] args) { private static io.temporal.common.SearchAttributes generateTypedSearchAttributes() { return io.temporal.common.SearchAttributes.newBuilder() .set(CUSTOM_KEYWORD_SA, "keyword") + .set(CUSTOM_KEYWORD_LIST_SA, Arrays.asList("how", "are", "you", "doing?")) .set(CUSTOM_LONG_SA, 1l) .set(CUSTOM_DOUBLE_SA, 0.1) .set(CUSTOM_BOOL_SA, true) From 97f19979e91cf0c5ed4d96c804ed0061785dd7e7 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 30 Apr 2024 09:43:24 -0700 Subject: [PATCH 160/240] Update Java SDK to v1.23.2 (#617) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a31abc5ab..432b0540f 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.23.1' + javaSDKVersion = '1.23.2' camelVersion = '3.22.1' jarVersion = '1.0.0' } From 7f51623cc2c3b9ace464e6a18c71f9717028f22e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 May 2024 12:03:00 -0400 Subject: [PATCH 161/240] Bump io.cloudevents:cloudevents-json-jackson from 2.5.0 to 3.0.0 (#609) Bumps io.cloudevents:cloudevents-json-jackson from 2.5.0 to 3.0.0. --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-json-jackson dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 68c005aae..4f6f1ddfb 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -26,7 +26,7 @@ dependencies { implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.5.0' - implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '2.5.0' + implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '3.0.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.5.Final' From 532c6a03759018ef1ccfdb5cff572f3ca3b627db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 May 2024 12:03:29 -0400 Subject: [PATCH 162/240] Bump io.cloudevents:cloudevents-core from 2.5.0 to 3.0.0 (#610) Bumps [io.cloudevents:cloudevents-core](https://github.com/cloudevents/sdk-java) from 2.5.0 to 3.0.0. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.5.0...3.0.0) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-core dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4f6f1ddfb..51b30ee41 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -24,7 +24,7 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' - implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '2.5.0' + implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '3.0.0' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.5.0' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '3.0.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.5.Final' From 01b6ba14b7e98378e9de960a89958fcdd8973ce3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 May 2024 16:12:58 +0000 Subject: [PATCH 163/240] Bump io.cloudevents:cloudevents-api from 2.5.0 to 3.0.0 (#611) Bumps [io.cloudevents:cloudevents-api](https://github.com/cloudevents/sdk-java) from 2.5.0 to 3.0.0. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/2.5.0...3.0.0) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-api dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 51b30ee41..63cbeac50 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -25,7 +25,7 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '3.0.0' - implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '2.5.0' + implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '3.0.0' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '3.0.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.5.Final' From 2ae69bc8922d54d8895c47a23318662d2aa9ba42 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Sun, 5 May 2024 15:00:25 -0400 Subject: [PATCH 164/240] update springboot camel sample (#618) Signed-off-by: Tihomir Surdilovic --- .../temporal/samples/springboot/camel/CamelRoutes.java | 9 +++++++++ .../samples/springboot/camel/OrderActivityImpl.java | 9 +++++++-- .../java/io/temporal/samples/springboot/camel/README.md | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java index 42d964650..9bf96dce3 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java @@ -29,6 +29,7 @@ public class CamelRoutes extends RouteBuilder { @Autowired private WorkflowClient workflowClient; + @Autowired OrderRepository repository; @Override public void configure() { @@ -47,5 +48,13 @@ public void configure() { exchange.getIn().setBody(workflow.start()); }) .end(); + + from("direct:findAllOrders") + .routeId("direct-findAllOrders") + .process( + exchange -> { + exchange.getIn().setBody(repository.findAll()); + }) + .end(); } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java index f87b5c5b4..088fdb9f3 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java @@ -21,6 +21,7 @@ import io.temporal.spring.boot.ActivityImpl; import java.util.List; +import org.apache.camel.ProducerTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -28,10 +29,14 @@ @ActivityImpl(taskQueues = "CamelSampleTaskQueue") public class OrderActivityImpl implements OrderActivity { - @Autowired OrderRepository repository; + @Autowired private ProducerTemplate producerTemplate; @Override public List getOrders() { - return repository.findAll(); + producerTemplate.start(); + List orders = + producerTemplate.requestBody("direct:findAllOrders", null, List.class); + producerTemplate.stop(); + return orders; } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/README.md b/springboot/src/main/java/io/temporal/samples/springboot/camel/README.md index f2d374dc5..9661b1aea 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/README.md +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/README.md @@ -8,5 +8,5 @@ http://localhost:3030/orders -This sample starts an Apache Camel route which runs our orders Workflow. -Results of the workflow are returned by the Camel route \ No newline at end of file +This sample starts an Apache Camel route which starts our orders Workflow. +The workflow starts an activity which starts Camel route to get all orders JPA. \ No newline at end of file From d4ede4a56ac69d6856e52ee5fa1eed6b18710d1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 23:44:14 -0400 Subject: [PATCH 165/240] Bump gradle/wrapper-validation-action from 2 to 3 (#614) Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from 2 to 3. - [Release notes](https://github.com/gradle/wrapper-validation-action/releases) - [Commits](https://github.com/gradle/wrapper-validation-action/compare/v2...v3) --- updated-dependencies: - dependency-name: gradle/wrapper-validation-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gradle-wrapper-validation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index f5ccf04c7..eb00f93cd 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -7,4 +7,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v2 + - uses: gradle/wrapper-validation-action@v3 From 201484496d3930a3199eca2ce60dbe6cc4e00275 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 23:44:49 -0400 Subject: [PATCH 166/240] Bump com.google.errorprone:error_prone_core from 2.26.1 to 2.27.1 (#619) Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.26.1 to 2.27.1. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.26.1...v2.27.1) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- springboot-basic/build.gradle | 4 ++-- springboot/build.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 63cbeac50..4470d04b2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -46,7 +46,7 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.26.1') + errorprone('com.google.errorprone:error_prone_core:2.27.1') } } diff --git a/springboot-basic/build.gradle b/springboot-basic/build.gradle index 42b8637aa..da2db6d5d 100644 --- a/springboot-basic/build.gradle +++ b/springboot-basic/build.gradle @@ -10,9 +10,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.26.1') + errorprone('com.google.errorprone:error_prone_core:2.27.1') } else { - errorprone('com.google.errorprone:error_prone_core:2.26.1') + errorprone('com.google.errorprone:error_prone_core:2.27.1') } } } diff --git a/springboot/build.gradle b/springboot/build.gradle index 7ae490cae..2ad026db5 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation "org.springframework.boot:spring-boot-starter-test" dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.26.1') + errorprone('com.google.errorprone:error_prone_core:2.27.1') } } From 9d75b489b2388321d4dfcc5f3e679800d900ba61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 23:45:13 -0400 Subject: [PATCH 167/240] Bump com.fasterxml.jackson:jackson-bom from 2.17.0 to 2.17.1 (#620) Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.17.0 to 2.17.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.17.0...jackson-bom-2.17.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4470d04b2..2ed130fad 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:$javaSDKVersion") // Needed for SDK related functionality - implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.0")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.1")) implementation "com.fasterxml.jackson.core:jackson-databind" implementation "com.fasterxml.jackson.core:jackson-core" From 323294aa3db343653062a5cf463145616adb4161 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 23:45:37 -0400 Subject: [PATCH 168/240] Bump ch.qos.logback:logback-classic from 1.5.3 to 1.5.6 (#621) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.5.3 to 1.5.6. - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.3...v_1.5.6) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 2ed130fad..a96e18e55 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation "io.micrometer:micrometer-registry-prometheus" - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.3' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.6' implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' implementation(platform("io.opentelemetry:opentelemetry-bom:$otelVersion")) From 92350ae86e0727c68ce726b701124c621bf12941 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 10:29:54 -0400 Subject: [PATCH 169/240] Bump org.mockito:mockito-core from 5.11.0 to 5.12.0 (#624) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.11.0 to 5.12.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.11.0...v5.12.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index a96e18e55..885767581 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation 'com.codingrodent:jackson-json-crypto:1.1.0' testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.11.0" + testImplementation "org.mockito:mockito-core:5.12.0" testImplementation(platform("org.junit:junit-bom:5.10.2")) testImplementation "org.junit.jupiter:junit-jupiter-api" From 35ebce6602037922878c7c72d9463af17db81069 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Thu, 27 Jun 2024 15:17:51 -0700 Subject: [PATCH 170/240] Update Java SDK (#636) --- build.gradle | 2 +- springboot-basic/build.gradle | 2 +- springboot-basic/src/main/resources/application-tc.yaml | 2 +- springboot/build.gradle | 2 +- springboot/src/main/resources/application-tc.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 432b0540f..6c3acfa10 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.23.2' + javaSDKVersion = '1.24.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/springboot-basic/build.gradle b/springboot-basic/build.gradle index da2db6d5d..6c9bfdd91 100644 --- a/springboot-basic/build.gradle +++ b/springboot-basic/build.gradle @@ -4,7 +4,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-web" implementation "org.springframework.boot:spring-boot-starter-thymeleaf" implementation "org.springframework.boot:spring-boot-starter-actuator" - implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" + implementation "io.temporal:temporal-spring-boot-starter:$javaSDKVersion" testImplementation "org.springframework.boot:spring-boot-starter-test" runtimeOnly "io.micrometer:micrometer-registry-prometheus" dependencies { diff --git a/springboot-basic/src/main/resources/application-tc.yaml b/springboot-basic/src/main/resources/application-tc.yaml index 041d67e06..45fb5a08a 100644 --- a/springboot-basic/src/main/resources/application-tc.yaml +++ b/springboot-basic/src/main/resources/application-tc.yaml @@ -6,4 +6,4 @@ spring.temporal: key-file: /path/to/key.key cert-chain-file: /path/to/cert.pem -# more configuration options https://github.com/temporalio/sdk-java/tree/master/temporal-spring-boot-autoconfigure-alpha#mtls \ No newline at end of file +# more configuration options https://github.com/temporalio/sdk-java/tree/master/temporal-spring-boot-autoconfigure#mtls \ No newline at end of file diff --git a/springboot/build.gradle b/springboot/build.gradle index 2ad026db5..a49c730e1 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -8,7 +8,7 @@ dependencies { implementation "org.springframework.kafka:spring-kafka" // we set this as impl depends to use embedded kafka in samples not just tests implementation "org.springframework.kafka:spring-kafka-test" - implementation "io.temporal:temporal-spring-boot-starter-alpha:$javaSDKVersion" + implementation "io.temporal:temporal-spring-boot-starter:$javaSDKVersion" implementation "org.apache.camel.springboot:camel-spring-boot-starter:$camelVersion" implementation "org.apache.camel.springboot:camel-servlet-starter:$camelVersion" runtimeOnly "io.micrometer:micrometer-registry-prometheus" diff --git a/springboot/src/main/resources/application-tc.yaml b/springboot/src/main/resources/application-tc.yaml index 041d67e06..45fb5a08a 100644 --- a/springboot/src/main/resources/application-tc.yaml +++ b/springboot/src/main/resources/application-tc.yaml @@ -6,4 +6,4 @@ spring.temporal: key-file: /path/to/key.key cert-chain-file: /path/to/cert.pem -# more configuration options https://github.com/temporalio/sdk-java/tree/master/temporal-spring-boot-autoconfigure-alpha#mtls \ No newline at end of file +# more configuration options https://github.com/temporalio/sdk-java/tree/master/temporal-spring-boot-autoconfigure#mtls \ No newline at end of file From d47356c5d6cf6cd8106058b9067a401bfa2d37b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 17:00:53 -0400 Subject: [PATCH 171/240] Bump com.google.errorprone:error_prone_core from 2.27.1 to 2.28.0 (#630) Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.27.1 to 2.28.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.27.1...v2.28.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- springboot-basic/build.gradle | 4 ++-- springboot/build.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 885767581..22a5fa4f8 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -46,7 +46,7 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.27.1') + errorprone('com.google.errorprone:error_prone_core:2.28.0') } } diff --git a/springboot-basic/build.gradle b/springboot-basic/build.gradle index 6c9bfdd91..abb58290d 100644 --- a/springboot-basic/build.gradle +++ b/springboot-basic/build.gradle @@ -10,9 +10,9 @@ dependencies { dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') if (JavaVersion.current().isJava11Compatible()) { - errorprone('com.google.errorprone:error_prone_core:2.27.1') + errorprone('com.google.errorprone:error_prone_core:2.28.0') } else { - errorprone('com.google.errorprone:error_prone_core:2.27.1') + errorprone('com.google.errorprone:error_prone_core:2.28.0') } } } diff --git a/springboot/build.gradle b/springboot/build.gradle index a49c730e1..7120304e9 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation "org.springframework.boot:spring-boot-starter-test" dependencies { errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - errorprone('com.google.errorprone:error_prone_core:2.27.1') + errorprone('com.google.errorprone:error_prone_core:2.28.0') } } From d742a3f62f7feeb918f3b5a27d8fccea7889e478 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 17:01:40 -0400 Subject: [PATCH 172/240] Bump net.ltgt.errorprone from 3.1.0 to 4.0.1 (#634) Bumps net.ltgt.errorprone from 3.1.0 to 4.0.1. --- updated-dependencies: - dependency-name: net.ltgt.errorprone dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6c3acfa10..ee7a9a661 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'org.cadixdev.licenser' version '0.6.1' - id "net.ltgt.errorprone" version "3.1.0" + id "net.ltgt.errorprone" version "4.0.1" id 'com.diffplug.spotless' version '6.25.0' apply false id "org.springframework.boot" version "${springBootPluginVersion}" } From d9946002a58230d092c0dff88e935732e6d38ebc Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Sun, 30 Jun 2024 14:02:48 -0700 Subject: [PATCH 173/240] Add details showing how to refresh mTLS (#628) --- .../java/io/temporal/samples/ssl/README.md | 10 ++++- .../java/io/temporal/samples/ssl/Starter.java | 41 ++++++++++++++++--- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/ssl/README.md b/core/src/main/java/io/temporal/samples/ssl/README.md index a48d7aedf..0bf762457 100644 --- a/core/src/main/java/io/temporal/samples/ssl/README.md +++ b/core/src/main/java/io/temporal/samples/ssl/README.md @@ -19,7 +19,13 @@ Before running the example you need to export the following env variables: ./gradlew -q execute -PmainClass=io.temporal.samples.ssl.Starter ``` -## Run SslEnabledWorkerCustomCA Sample +## Refreshing credentials + +- TEMPORAL_CREDENTIAL_REFRESH_PERIOD: The period in seconds to refresh the credentials in minutes. + +Setting this env variable will cause the worker to periodically update its credentials. For the full documentation see [here](https://grpc.github.io/grpc-java/javadoc/io/grpc/util/AdvancedTlsX509KeyManager.html). + +# Workflow execution with mTLS and custom Certificate Authority This sample shows how to start a worker that connects to a temporal cluster with mTLS enabled; created by ([tls-simple sample](https://github.com/temporalio/samples-server/tree/main/tls/tls-simple)); @@ -28,6 +34,8 @@ SslEnabledWorkerCustomCA demonstrates: - Passing a custom CA certificate file as parameter - Overriding the authority name used for TLS handshakes (if needed) +This can be useful when connecting to Temporal Cloud through [AWS Privatelink](https://docs.temporal.io/cloud/security#privatelink) + 1.Start a temporal cluster with tls Please follow the temporal server-sample to start simple Temporal mTLS cluster locally: [tls-simple](https://github.com/temporalio/samples-server/tree/main/tls/tls-simple) diff --git a/core/src/main/java/io/temporal/samples/ssl/Starter.java b/core/src/main/java/io/temporal/samples/ssl/Starter.java index b61b3b761..ca748ffc3 100644 --- a/core/src/main/java/io/temporal/samples/ssl/Starter.java +++ b/core/src/main/java/io/temporal/samples/ssl/Starter.java @@ -19,6 +19,10 @@ package io.temporal.samples.ssl; +import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; +import io.grpc.util.AdvancedTlsX509KeyManager; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowOptions; @@ -27,8 +31,10 @@ import io.temporal.serviceclient.WorkflowServiceStubsOptions; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.File; import java.io.FileInputStream; -import java.io.InputStream; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; public class Starter { @@ -40,22 +46,45 @@ public static void main(String[] args) throws Exception { // -----BEGIN CERTIFICATE----- // ... // -----END CERTIFICATE----- - InputStream clientCert = new FileInputStream(System.getenv("TEMPORAL_CLIENT_CERT")); + File clientCertFile = new File(System.getenv("TEMPORAL_CLIENT_CERT")); // PKCS8 client key, which should look like: // -----BEGIN PRIVATE KEY----- // ... // -----END PRIVATE KEY----- - InputStream clientKey = new FileInputStream(System.getenv("TEMPORAL_CLIENT_KEY")); + File clientKeyFile = new File(System.getenv("TEMPORAL_CLIENT_KEY")); // For temporal cloud this would likely be ${namespace}.tmprl.cloud:7233 String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT"); // Your registered namespace. String namespace = System.getenv("TEMPORAL_NAMESPACE"); + // How often to refresh the client key and certificate + String refreshPeriodString = System.getenv("TEMPORAL_CREDENTIAL_REFRESH_PERIOD"); + long refreshPeriod = refreshPeriodString != null ? Integer.parseInt(refreshPeriodString) : 0; + // Create SSL context from SimpleSslContextBuilder + SslContext sslContext = + SimpleSslContextBuilder.forPKCS8( + new FileInputStream(clientCertFile), new FileInputStream(clientKeyFile)) + .build(); + // To refresh the client key and certificate, create an AdvancedTlsX509KeyManager and manually + // configure the SSL context. + if (refreshPeriod > 0) { + AdvancedTlsX509KeyManager clientKeyManager = new AdvancedTlsX509KeyManager(); + // Reload credentials every minute + clientKeyManager.updateIdentityCredentialsFromFile( + clientKeyFile, + clientCertFile, + refreshPeriod, + TimeUnit.MINUTES, + Executors.newScheduledThreadPool(1)); + sslContext = + GrpcSslContexts.configure(SslContextBuilder.forClient().keyManager(clientKeyManager)) + .build(); + } - // Create SSL enabled client by passing SslContext, created by SimpleSslContextBuilder. + // Create SSL enabled client by passing SslContext WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs( WorkflowServiceStubsOptions.newBuilder() - .setSslContext(SimpleSslContextBuilder.forPKCS8(clientCert, clientKey).build()) + .setSslContext(sslContext) .setTarget(targetEndpoint) .build()); @@ -110,6 +139,6 @@ public static void main(String[] args) throws Exception { // Display workflow execution results System.out.println(greeting); - System.exit(0); + // System.exit(0); } } From 051b925aeeb2b02681ab88a6338730c717bd19be Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 2 Jul 2024 12:26:13 -0400 Subject: [PATCH 174/240] SpringBoot test with mocked activity (#637) Signed-off-by: Tihomir Surdilovic --- .../HelloSampleTestMockedActivity.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTestMockedActivity.java diff --git a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTestMockedActivity.java b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTestMockedActivity.java new file mode 100644 index 000000000..53f62ee0d --- /dev/null +++ b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTestMockedActivity.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot; + +import static org.mockito.ArgumentMatchers.any; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.springboot.hello.HelloActivity; +import io.temporal.samples.springboot.hello.HelloActivityImpl; +import io.temporal.samples.springboot.hello.HelloWorkflow; +import io.temporal.samples.springboot.hello.model.Person; +import io.temporal.testing.TestWorkflowEnvironment; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Primary; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.util.Assert; + +@SpringBootTest(classes = HelloSampleTestMockedActivity.Configuration.class) +@ActiveProfiles("test") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +// set this to omit setting up embedded kafka +@EnableAutoConfiguration(exclude = {KafkaAutoConfiguration.class}) +@DirtiesContext +public class HelloSampleTestMockedActivity { + + @Autowired ConfigurableApplicationContext applicationContext; + + @Autowired TestWorkflowEnvironment testWorkflowEnvironment; + + @Autowired WorkflowClient workflowClient; + + @Captor ArgumentCaptor personArgumentCaptor; + + @Autowired HelloActivity activity; + + @BeforeEach + void setUp() { + applicationContext.start(); + } + + @Test + public void testHello() { + HelloWorkflow workflow = + workflowClient.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue("HelloSampleTaskQueue") + .setWorkflowId("HelloSampleTest") + .build()); + String result = workflow.sayHello(new Person("Temporal", "User")); + Assert.notNull(result, "Greeting should not be null"); + Assert.isTrue(result.equals("Hello from mocked activity"), "Invalid result"); + + Mockito.verify(activity, Mockito.times(1)).hello(personArgumentCaptor.capture()); + Assert.notNull(personArgumentCaptor.getValue(), "Invalid input"); + Assert.isTrue( + personArgumentCaptor.getValue().getFirstName().equals("Temporal"), + "Invalid person first name"); + Assert.isTrue( + personArgumentCaptor.getValue().getLastName().equals("User"), "invalid person last name"); + } + + @ComponentScan + public static class Configuration { + @MockBean private HelloActivityImpl helloActivityMock; + + @Bean + @Primary + public HelloActivity getTestActivityImpl() { + Mockito.when(helloActivityMock.hello(any())).thenReturn("Hello from mocked activity"); + return helloActivityMock; + } + } +} From 825ca129aa1c4ddd1c6a4c55125f55c20be37d74 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 2 Jul 2024 12:26:26 -0400 Subject: [PATCH 175/240] emporalOptionsCustomizer for WorkflowImplementationOpt (#638) Signed-off-by: Tihomir Surdilovic --- .../customize/TemporalOptionsConfig.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java index cfe046707..5ce82d019 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java @@ -25,6 +25,7 @@ import io.temporal.spring.boot.WorkerOptionsCustomizer; import io.temporal.worker.WorkerFactoryOptions; import io.temporal.worker.WorkerOptions; +import io.temporal.worker.WorkflowImplementationOptions; import javax.annotation.Nonnull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -98,4 +99,19 @@ public WorkerFactoryOptions.Builder customize( } }; } + + // WorkflowImplementationOptions customization + @Bean + public TemporalOptionsCustomizer + customWorkflowImplementationOptions() { + return new TemporalOptionsCustomizer<>() { + @Nonnull + @Override + public WorkflowImplementationOptions.Builder customize( + @Nonnull WorkflowImplementationOptions.Builder optionsBuilder) { + // set options on optionsBuilder such as per-activity options + return optionsBuilder; + } + }; + } } From ad76b88030be52fadc68e6b36ae7d26fcf4ed533 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 2 Jul 2024 12:26:40 -0400 Subject: [PATCH 176/240] spring boot custom actuator worker endpoint sample (#639) Signed-off-by: Tihomir Surdilovic --- README.md | 1 + .../samples/springboot/SamplesController.java | 6 + .../samples/springboot/actuator/README.md | 13 +++ .../actuator/WorkerActuatorEndpoint.java | 107 ++++++++++++++++++ .../src/main/resources/application.yaml | 2 +- .../main/resources/templates/actuator.html | 20 ++++ .../src/main/resources/templates/index.html | 3 + 7 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/actuator/README.md create mode 100644 springboot/src/main/java/io/temporal/samples/springboot/actuator/WorkerActuatorEndpoint.java create mode 100644 springboot/src/main/resources/templates/actuator.html diff --git a/README.md b/README.md index f04500e19..9b7edfbcd 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,7 @@ More info on each sample: - [**Kafka Request / Reply**](/springboot/src/main/java/io/temporal/samples/springboot/kafka): Sample showing possible integration with event streaming platforms such as Kafka - [**Customize Options**](/springboot/src/main/java/io/temporal/samples/springboot/customize): Sample showing how to customize options such as WorkerOptions, WorkerFactoryOptions, etc (see options config [here](springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java)) - [**Apache Camel Route**](/springboot/src/main/java/io/temporal/samples/springboot/camel): Sample showing how to start Workflow execution from a Camel Route +- [**Custom Actuator Endpoint**](/springboot/src/main/java/io/temporal/samples/springboot/actuator): Sample showing how to create a custom Actuator endpoint that shows registered Workflow and Activity impls per task queue. #### Temporal Cloud To run any of the SpringBoot samples in your Temporal Cloud namespace: diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index a9799d096..814236e09 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -182,4 +182,10 @@ public String camel(Model model) { model.addAttribute("sample", "Camel Route"); return "camel"; } + + @GetMapping("/customendpoint") + public String customEndpoint(Model model) { + model.addAttribute("sample", "Custom Actuator Worker Info Endpoint"); + return "actuator"; + } } diff --git a/springboot/src/main/java/io/temporal/samples/springboot/actuator/README.md b/springboot/src/main/java/io/temporal/samples/springboot/actuator/README.md new file mode 100644 index 000000000..ab24690e6 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/actuator/README.md @@ -0,0 +1,13 @@ +# SpringBoot Actuator Worker Info Endpoint - Sample + +1. Start SpringBoot from main samples repo directory: + + ./gradlew bootRun + +2. In your browser navigate to: + + http://localhost:3030/actuator/temporalworkerinfo + +This sample shows how to create a custom Actuator Endpoint that +displays registered workflow and activity implementations per task queue. +This information comes from actually registered workers done by autoconfig module. \ No newline at end of file diff --git a/springboot/src/main/java/io/temporal/samples/springboot/actuator/WorkerActuatorEndpoint.java b/springboot/src/main/java/io/temporal/samples/springboot/actuator/WorkerActuatorEndpoint.java new file mode 100644 index 000000000..140bf2847 --- /dev/null +++ b/springboot/src/main/java/io/temporal/samples/springboot/actuator/WorkerActuatorEndpoint.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.springboot.actuator; + +import io.temporal.common.metadata.*; +import io.temporal.spring.boot.autoconfigure.template.WorkersTemplate; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.stereotype.Component; + +@Component +@Endpoint(id = "temporalworkerinfo") +public class WorkerActuatorEndpoint { + @Autowired + @Qualifier("temporalWorkersTemplate") + private WorkersTemplate workersTemplate; + + @ReadOperation + public String workerInfo() { + StringBuilder sb = new StringBuilder(); + Map registeredInfo = + workersTemplate.getRegisteredInfo(); + sb.append("Worker Info:"); + registeredInfo.forEach( + (taskQueue, info) -> { + sb.append("\n\n\tTask Queue: ").append(taskQueue); + info.getRegisteredWorkflowInfo() + .forEach( + (workflowInfo) -> { + sb.append("\n\t\t Workflow Interface: ").append(workflowInfo.getClassName()); + POJOWorkflowImplMetadata metadata = workflowInfo.getMetadata(); + sb.append("\n\t\t\t Workflow Methods: "); + sb.append( + metadata.getWorkflowMethods().stream() + .map(POJOWorkflowMethodMetadata::getWorkflowMethod) + .map(Method::getName) + .collect(Collectors.joining(", "))); + sb.append("\n\t\t\t Query Methods: "); + sb.append( + metadata.getQueryMethods().stream() + .map(POJOWorkflowMethodMetadata::getWorkflowMethod) + .map(Method::getName) + .collect(Collectors.joining(", "))); + sb.append("\n\t\t\t Signal Methods: "); + sb.append( + metadata.getSignalMethods().stream() + .map(POJOWorkflowMethodMetadata::getWorkflowMethod) + .map(Method::getName) + .collect(Collectors.joining(", "))); + sb.append("\n\t\t\t Update Methods: "); + sb.append( + metadata.getUpdateMethods().stream() + .map(POJOWorkflowMethodMetadata::getWorkflowMethod) + .map(Method::getName) + .collect(Collectors.joining(","))); + sb.append("\n\t\t\t Update Validator Methods: "); + sb.append( + metadata.getUpdateValidatorMethods().stream() + .map(POJOWorkflowMethodMetadata::getWorkflowMethod) + .map(Method::getName) + .collect(Collectors.joining(", "))); + }); + info.getRegisteredActivityInfo() + .forEach( + (activityInfo) -> { + sb.append("\n\t\t Activity Impl: ").append(activityInfo.getClassName()); + POJOActivityImplMetadata metadata = activityInfo.getMetadata(); + sb.append("\n\t\t\t Activity Interfaces: "); + sb.append( + metadata.getActivityInterfaces().stream() + .map(POJOActivityInterfaceMetadata::getInterfaceClass) + .map(Class::getName) + .collect(Collectors.joining(","))); + sb.append("\n\t\t\t Activity Methods: "); + sb.append( + metadata.getActivityMethods().stream() + .map(POJOActivityMethodMetadata::getMethod) + .map(Method::getName) + .collect(Collectors.joining(", "))); + }); + }); + + return sb.toString(); + } +} diff --git a/springboot/src/main/resources/application.yaml b/springboot/src/main/resources/application.yaml index 7722f9762..535468336 100644 --- a/springboot/src/main/resources/application.yaml +++ b/springboot/src/main/resources/application.yaml @@ -49,7 +49,7 @@ management: endpoints: web: exposure: - include: prometheus + include: prometheus,temporalworkerinfo # specific for samples samples: data: diff --git a/springboot/src/main/resources/templates/actuator.html b/springboot/src/main/resources/templates/actuator.html new file mode 100644 index 000000000..a8f6edb98 --- /dev/null +++ b/springboot/src/main/resources/templates/actuator.html @@ -0,0 +1,20 @@ + + + + +

+
+
+

Temporal Java SDK Samples

+
In this sample we show how to create a custom Actuator Endpoint showing Worker Info.
+

+
+
Spring Actuator allows + us to create custom endpoints. This sample shows how to create a Worker Info custom endpoint that shows registered Workflow and Activity impls per task queue.

+ View the custom endpoint at localhost:3030/actuator/temporalworkerinfo +
+
+
+
+ + \ No newline at end of file diff --git a/springboot/src/main/resources/templates/index.html b/springboot/src/main/resources/templates/index.html index 34df6ec12..c62f97ac5 100644 --- a/springboot/src/main/resources/templates/index.html +++ b/springboot/src/main/resources/templates/index.html @@ -25,6 +25,9 @@
Temporal Java SDK Samples
+
From f666773430d8b082c382fe26ad65aa1f4bc45f80 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Mon, 8 Jul 2024 11:43:21 -0400 Subject: [PATCH 177/240] Adding accumulator pattern sample (#616) * adding hello accumulator * updates * Accumulator: adding a test for signal after exit signal, switching out default tests in main * feedback from PR: switching to interface for Deque; removing unnecessary clauses in accumulateGreetings() and processGreeting(); clarifying bad bucket checks * renaming variables and functions based on code review * improvement from code review, setting license to match required license * Accepting Tiho's suggestion to process signals in-loop, reducing use of timers --- README.md | 2 + .../samples/hello/HelloAccumulator.java | 634 ++++++++++++++++++ .../java/io/temporal/samples/hello/README.md | 1 + .../samples/hello/HelloAccumulatorTest.java | 433 ++++++++++++ 4 files changed, 1070 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloAccumulatorTest.java diff --git a/README.md b/README.md index 9b7edfbcd..216496b2c 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman #### Hello samples - [**Hello**](/core/src/main/java/io/temporal/samples/hello): This sample includes a number of individual Workflows that can be executed independently. Each one demonstrates something specific. + + - [**HelloAccumulator**](/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java): Demonstrates a Workflow Definition that accumulates signals and continues as new. - [**HelloActivity**](/core/src/main/java/io/temporal/samples/hello/HelloActivity.java): Demonstrates a Workflow Definition that executes a single Activity. - [**HelloActivityRetry**](/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java): Demonstrates how to Retry an Activity Execution. - [**HelloActivityExclusiveChoice**](/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java): Demonstrates how to execute Activities based on dynamic input. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java b/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java new file mode 100644 index 000000000..c5561df09 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityOptions; +import io.temporal.api.workflow.v1.WorkflowExecutionInfo; +import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionRequest; +import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionResponse; +import io.temporal.client.BatchRequest; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowNotFoundException; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.io.Serializable; +import java.time.Duration; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * Sample Temporal Workflow Definition that accumulates events. + * This sample implements the Accumulator Pattern: collect many meaningful + * things that need to be collected and worked on together, such as + * all payments for an account, or all account updates by account. + * + * This sample models robots being created throughout the time period, + * groups them by what color they are, and greets all the robots + * of a color at the end. + * + * A new workflow is created per grouping. Workflows continue as new as needed. + * A sample activity at the end is given, and you could add an activity to + * process individual events in the processGreeting() method. + */ +public class HelloAccumulator { + // set a time to wait for another signal to come in, e.g. + // Duration.ofDays(30); + static final Duration MAX_AWAIT_TIME = Duration.ofMinutes(1); + + static final String TASK_QUEUE = "HelloAccumulatorTaskQueue"; + static final String WORKFLOW_ID_PREFIX = "HelloAccumulatorWorkflow"; + + public static class Greeting implements Serializable { + String greetingText; + String bucket; + String greetingKey; + + public String getGreetingText() { + return greetingText; + } + + public void setGreetingText(String greetingText) { + this.greetingText = greetingText; + } + + public String getBucket() { + return bucket; + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } + + public String getGreetingKey() { + return greetingKey; + } + + public void setGreetingKey(String greetingKey) { + this.greetingKey = greetingKey; + } + + public Greeting(String greetingText, String bucket, String greetingKey) { + this.greetingText = greetingText; + this.bucket = bucket; + this.greetingKey = greetingKey; + } + + public Greeting() {} + + @Override + public String toString() { + return "Greeting [greetingText=" + + greetingText + + ", bucket=" + + bucket + + ", greetingKey=" + + greetingKey + + "]"; + } + } + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see io.temporal.workflow.WorkflowInterface + * @see io.temporal.workflow.WorkflowMethod + */ + @WorkflowInterface + public interface AccumulatorWorkflow { + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + String accumulateGreetings( + String bucketKey, Deque greetings, Set allGreetingsSet); + + // Define the workflow sendGreeting signal method. This method is executed when + // the workflow receives a greeting signal. + @SignalMethod + void sendGreeting(Greeting greeting); + + // Define the workflow exit signal method. This method is executed when the + // workflow receives an exit signal. + @SignalMethod + void exit(); + } + + /** + * This is the Activity Definition's Interface. Activities are building blocks of any Temporal + * Workflow and contain any business logic that could perform long running computation, network + * calls, etc. + * + *

Annotating Activity Definition methods with @ActivityMethod is optional. + * + * @see io.temporal.activity.ActivityInterface + * @see io.temporal.activity.ActivityMethod + */ + @ActivityInterface + public interface GreetingActivities { + String composeGreeting(Deque greetings); + } + + /** Simple activity implementation. */ + static class GreetingActivitiesImpl implements GreetingActivities { + + // here is where we process all of the signals together + @Override + public String composeGreeting(Deque greetings) { + List greetingList = + greetings.stream().map(u -> u.greetingText).collect(Collectors.toList()); + return "Hello (" + greetingList.size() + ") robots: " + greetingList + "!"; + } + } + + // Main workflow method + public static class AccumulatorWorkflowImpl implements AccumulatorWorkflow { + + private final GreetingActivities activities = + Workflow.newActivityStub( + GreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + private static final Logger logger = LoggerFactory.getLogger(AccumulatorWorkflowImpl.class); + String bucketKey; + ArrayDeque greetings; + HashSet allGreetingsSet; + boolean exitRequested = false; + ArrayDeque unprocessedGreetings = new ArrayDeque(); + + @Override + public String accumulateGreetings( + String bucketKeyInput, Deque greetingsInput, Set allGreetingsSetInput) { + bucketKey = bucketKeyInput; + greetings = new ArrayDeque(); + allGreetingsSet = new HashSet(); + greetings.addAll(greetingsInput); + allGreetingsSet.addAll(allGreetingsSetInput); + + // If you want to wait for a fixed amount of time instead of a time after a + // message + // as this does now, you might want to check out + // ../../updatabletimer + + // Main Workflow Loop: + // - wait for signals to come in + // - every time a signal comes in, wait again for MAX_AWAIT_TIME + // - if time runs out, and there are no messages, process them all and exit + // - if exit signal is received, process any remaining signals and exit + do { + + boolean timedout = + !Workflow.await(MAX_AWAIT_TIME, () -> !unprocessedGreetings.isEmpty() || exitRequested); + + while (!unprocessedGreetings.isEmpty()) { + processGreeting(unprocessedGreetings.removeFirst()); + } + + if (exitRequested || timedout) { + String greetEveryone = processGreetings(greetings); + + if (unprocessedGreetings.isEmpty()) { + logger.info("Greeting queue is still empty"); + return greetEveryone; + } else { + // you can get here if you send a signal after an exit, causing rollback just + // after the + // last processed activity + logger.info("Greeting queue not empty, looping"); + } + } + } while (!unprocessedGreetings.isEmpty() || !Workflow.getInfo().isContinueAsNewSuggested()); + + logger.info("starting continue as new processing"); + + // Create a workflow stub that will be used to continue this workflow as a new + AccumulatorWorkflow continueAsNew = Workflow.newContinueAsNewStub(AccumulatorWorkflow.class); + + // Request that the new run will be invoked by the Temporal system: + continueAsNew.accumulateGreetings(bucketKey, greetings, allGreetingsSet); + // this could be improved in the future with the are_handlers_finished API. For + // now if a signal comes in + // after this, it will fail the workflow task and retry handling the new + // signal(s) + + return "continued as new; results passed to next run"; + } + + // Here is where we can process individual signals as they come in. + // It's ok to call activities here. + // This also validates an individual greeting: + // - check for duplicates + // - check for correct bucket + public void processGreeting(Greeting greeting) { + logger.info("processing greeting-" + greeting); + if (greeting == null) { + logger.warn("Greeting is null:" + greeting); + return; + } + + // this just ignores incorrect buckets - you can use workflowupdate to validate + // and reject + // bad bucket requests if needed + if (!greeting.bucket.equals(bucketKey)) { + logger.warn("wrong bucket, something is wrong with your signal processing: " + greeting); + return; + } + + if (!allGreetingsSet.add(greeting.greetingKey)) { + logger.info("Duplicate signal event: " + greeting.greetingKey); + return; + } + + // add in any desired event processing activity here + greetings.add(greeting); + } + + private String processGreetings(Deque greetings) { + logger.info("Composing greetings for: " + greetings); + return activities.composeGreeting(greetings); + } + + // Signal method + // Keep it simple, these should be fast and not call activities + @Override + public void sendGreeting(Greeting greeting) { + // signals can be the first workflow code that runs, make sure we have + // an ArrayDeque to write to + if (unprocessedGreetings == null) { + unprocessedGreetings = new ArrayDeque(); + } + logger.info("received greeting-" + greeting); + unprocessedGreetings.add(greeting); + } + + @Override + public void exit() { + logger.info("exit signal received"); + exitRequested = true; + } + } + + /** + * With the Workflow and Activities defined, we can now start execution. The main method starts + * the worker and then the workflow. + */ + public static void main(String[] args) throws Exception { + + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query + * Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + client.getWorkflowServiceStubs().healthCheck(); + + /* + * Define the workflow factory. It is used to create workflow workers for a + * specific task queue. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue + * and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register the workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(AccumulatorWorkflowImpl.class); + + /* + * Register our Activity Types with the Worker. Since Activities are stateless + * and thread-safe, + * the Activity Type is a shared instance. + */ + worker.registerActivitiesImplementations(new GreetingActivitiesImpl()); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + System.out.println("Worker started for task queue: " + TASK_QUEUE); + + // setup which tests to run + // by default it will run an accumulation with a few (20) signals + // to a set of 4 buckets with Signal To Start + boolean testContinueAsNew = false; + + boolean testSignalEdgeCases = true; + // configure signal edge cases to test + boolean testSignalAfterWorkflowExit = true; + boolean testSignalAfterExitSignal = !testSignalAfterWorkflowExit; + boolean testDuplicate = true; + boolean testIgnoreBadBucket = true; + + // setup to send signals + String bucket = "blue"; + String workflowId = WORKFLOW_ID_PREFIX + "-" + bucket; + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + String greetingKey = "key-"; + String greetingText = "Robby Robot"; + Greeting starterGreeting = new Greeting(greetingText, bucket, greetingKey); + final String[] buckets = {"red", "blue", "green", "yellow"}; + final String[] names = {"Genghis Khan", "Missy", "Bill", "Ted", "Rufus", "Abe"}; + + // Create the workflow options + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(workflowId).build(); + AccumulatorWorkflow workflow = + client.newWorkflowStub(AccumulatorWorkflow.class, workflowOptions); + + // send many signals to start several workflows + int max_signals = 20; + + if (testContinueAsNew) max_signals = 10000; + for (int i = 0; i < max_signals; i++) { + Random randomBucket = new Random(); + int bucketIndex = randomBucket.nextInt(buckets.length); + bucket = buckets[bucketIndex]; + starterGreeting.setBucket(bucket); + Thread.sleep(20); // simulate some delay + + workflowId = WORKFLOW_ID_PREFIX + "-" + bucket; + + Random randomName = new Random(); + int nameIndex = randomName.nextInt(names.length); + starterGreeting.setGreetingText(names[nameIndex] + " Robot"); + + workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(workflowId).build(); + + // Create the workflow client stub. It is used to start the workflow execution. + workflow = client.newWorkflowStub(AccumulatorWorkflow.class, workflowOptions); + + BatchRequest request = client.newSignalWithStartRequest(); + starterGreeting.greetingKey = greetingKey + i; + request.add(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow::sendGreeting, starterGreeting); + client.signalWithStart(request); + } + + // Demonstrate we still can connect to WF and get result using untyped: + if (max_signals > 0) { + WorkflowStub untyped = WorkflowStub.fromTyped(workflow); + + // wait for it to finish + try { + String greeting = untyped.getResult(String.class); + printWorkflowStatus(client, workflowId); + System.out.println("Greeting: " + greeting); + } catch (WorkflowFailedException e) { + System.out.println("Workflow failed: " + e.getCause().getMessage()); + printWorkflowStatus(client, workflowId); + } + } + if (!testSignalEdgeCases) { + System.exit(0); // skip other demonstrations below + } + + // set workflow parameters + bucket = "purple"; + greetingList = new ArrayDeque(); + allGreetingsSet = new HashSet(); + workflowId = WORKFLOW_ID_PREFIX + "-" + bucket; + workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(workflowId).build(); + + starterGreeting = new Greeting("Suzy Robot", bucket, "11235813"); + + // Create the workflow client stub. It is used to start the workflow execution. + AccumulatorWorkflow workflowSync = + client.newWorkflowStub(AccumulatorWorkflow.class, workflowOptions); + + // Start workflow asynchronously and call its getGreeting workflow method + WorkflowClient.start(workflowSync::accumulateGreetings, bucket, greetingList, allGreetingsSet); + + // After start for accumulateGreetings returns, the workflow is guaranteed to be + // started, so we can send a signal to it using the workflow stub. + // This workflow keeps receiving signals until exit is called or the timer + // finishes with no + // signals + + // When the workflow is started the accumulateGreetings will block for the + // previously defined conditions + // Send the first workflow signal + workflowSync.sendGreeting(starterGreeting); + + // Test sending an exit, waiting for workflow exit, then sending a signal. + // This will trigger a WorkflowNotFoundException if using the same workflow + // handle + if (testSignalAfterWorkflowExit) { + workflowSync.exit(); + String greetingsAfterExit = + workflowSync.accumulateGreetings(bucket, greetingList, allGreetingsSet); + System.out.println(greetingsAfterExit); + } + + // Test sending an exit, not waiting for workflow to exit, then sending a signal + // this demonstrates Temporal history rollback + // see https://community.temporal.io/t/continueasnew-signals/1008/7 + if (testSignalAfterExitSignal) { + workflowSync.exit(); + } + + // Test sending more signals after workflow exit + try { + // send a second workflow signal + Greeting janeGreeting = new Greeting("Jane Robot", bucket, "112358132134"); + workflowSync.sendGreeting(janeGreeting); + + if (testIgnoreBadBucket) { + // send a third signal with an incorrect bucket - this will be ignored + // can use workflow update to validate and reject a request if needed + workflowSync.sendGreeting(new Greeting("Sally Robot", "taupe", "112358132134")); + } + + if (testDuplicate) { + // intentionally send a duplicate signal + workflowSync.sendGreeting(janeGreeting); + } + + if (!testSignalAfterWorkflowExit) { + // wait for results if we haven't waited for them yet + String greetingsAfterExit = + workflowSync.accumulateGreetings(bucket, greetingList, allGreetingsSet); + System.out.println(greetingsAfterExit); + } + } catch (WorkflowNotFoundException e) { + System.out.println("Workflow not found - this is intentional: " + e.getCause().getMessage()); + printWorkflowStatus(client, workflowId); + } + + try { + /* + * Here we create a new workflow stub using the same workflow id. + * We do this to demonstrate that to send a signal to an already running + * workflow you only need to know its workflow id. + */ + AccumulatorWorkflow workflowById = + client.newWorkflowStub(AccumulatorWorkflow.class, workflowId); + + Greeting laterGreeting = new Greeting("XVX Robot", bucket, "1123581321"); + // Send the second signal to our workflow + workflowById.sendGreeting(laterGreeting); + + // Now let's send our exit signal to the workflow + workflowById.exit(); + + /* + * We now call our accumulateGreetings workflow method synchronously after our + * workflow has started. + * This reconnects our workflowById workflow stub to the existing workflow and + * blocks until a result is available. Note that this behavior assumes that + * WorkflowOptions + * are not configured with WorkflowIdReusePolicy.AllowDuplicate. If they were, + * this call would fail + * with the WorkflowExecutionAlreadyStartedException exception. + * You can use the policy to force workflows for a new time period, e.g. a + * collection day, to have a new workflow ID. + */ + + String greetings = workflowById.accumulateGreetings(bucket, greetingList, allGreetingsSet); + + // Print our results for greetings which were sent by signals + System.out.println(greetings); + } catch (WorkflowNotFoundException e) { + System.out.println("Workflow not found - this is intentional: " + e.getCause().getMessage()); + printWorkflowStatus(client, workflowId); + } + + /* + * Here we try to send the signals as start to demonstrate that after a workflow + * exited + * and signals failed to send + * we can send signals to a new workflow + */ + if (testSignalAfterWorkflowExit) { + greetingList = new ArrayDeque(); + allGreetingsSet = new HashSet(); + workflowId = WORKFLOW_ID_PREFIX + "-" + bucket; + + Greeting laterGreeting = new Greeting("Final Robot", bucket, "1123"); + // Send the second signal to our workflow + + workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(workflowId).build(); + + // Create the workflow client stub. It is used to start the workflow execution. + workflow = client.newWorkflowStub(AccumulatorWorkflow.class, workflowOptions); + + BatchRequest request = client.newSignalWithStartRequest(); + request.add(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow::sendGreeting, laterGreeting); + client.signalWithStart(request); + + printWorkflowStatus(client, workflowId); + + String greetingsAfterExit = + workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + + // Print our results for greetings which were sent by signals + System.out.println(greetingsAfterExit); + + printWorkflowStatus(client, workflowId); + + while (getWorkflowStatus(client, workflowId).equals("WORKFLOW_EXECUTION_STATUS_RUNNING")) { + + System.out.println("Workflow still running "); + Thread.sleep(1000); + } + } + + System.exit(0); + } + + private static void printWorkflowStatus(WorkflowClient client, String workflowId) { + WorkflowStub existingUntyped = + client.newUntypedWorkflowStub(workflowId, Optional.empty(), Optional.empty()); + DescribeWorkflowExecutionRequest describeWorkflowExecutionRequest = + DescribeWorkflowExecutionRequest.newBuilder() + .setNamespace(client.getOptions().getNamespace()) + .setExecution(existingUntyped.getExecution()) + .build(); + + DescribeWorkflowExecutionResponse resp = + client + .getWorkflowServiceStubs() + .blockingStub() + .describeWorkflowExecution(describeWorkflowExecutionRequest); + System.out.println( + "**** PARENT: " + resp.getWorkflowExecutionInfo().getParentExecution().getWorkflowId()); + + WorkflowExecutionInfo workflowExecutionInfo = resp.getWorkflowExecutionInfo(); + System.out.println("Workflow Status: " + workflowExecutionInfo.getStatus().toString()); + } + + private static String getWorkflowStatus(WorkflowClient client, String workflowId) { + WorkflowStub existingUntyped = + client.newUntypedWorkflowStub(workflowId, Optional.empty(), Optional.empty()); + DescribeWorkflowExecutionRequest describeWorkflowExecutionRequest = + DescribeWorkflowExecutionRequest.newBuilder() + .setNamespace(client.getOptions().getNamespace()) + .setExecution(existingUntyped.getExecution()) + .build(); + + DescribeWorkflowExecutionResponse resp = + client + .getWorkflowServiceStubs() + .blockingStub() + .describeWorkflowExecution(describeWorkflowExecutionRequest); + System.out.println( + "**** PARENT: " + resp.getWorkflowExecutionInfo().getParentExecution().getWorkflowId()); + + WorkflowExecutionInfo workflowExecutionInfo = resp.getWorkflowExecutionInfo(); + return workflowExecutionInfo.getStatus().toString(); + } +} diff --git a/core/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md index 746d89c32..86eba613b 100644 --- a/core/src/main/java/io/temporal/samples/hello/README.md +++ b/core/src/main/java/io/temporal/samples/hello/README.md @@ -7,6 +7,7 @@ Each Hello World sample demonstrates one feature of the SDK in a single file. To run each hello world sample, use one of the following commands: ```bash +./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAccumulator ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivity ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivityRetry ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivityExclusiveChoice diff --git a/core/src/test/java/io/temporal/samples/hello/HelloAccumulatorTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAccumulatorTest.java new file mode 100644 index 000000000..53477bbd7 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloAccumulatorTest.java @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static io.temporal.samples.hello.HelloAccumulator.MAX_AWAIT_TIME; + +import io.temporal.client.BatchRequest; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.hello.HelloAccumulator.Greeting; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowRule; +import java.time.Duration; +import java.util.ArrayDeque; +import java.util.HashSet; +import org.junit.Rule; +import org.junit.Test; + +public class HelloAccumulatorTest { + + private TestWorkflowEnvironment testEnv; + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(HelloAccumulator.AccumulatorWorkflowImpl.class) + .setActivityImplementations(new HelloAccumulator.GreetingActivitiesImpl()) + .build(); + + @Test + public void testWorkflow() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + HelloAccumulator.AccumulatorWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + WorkflowClient.start(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + + Greeting xvxGreeting = new Greeting("XVX Robot", bucket, "1123581321"); + + workflow.sendGreeting(xvxGreeting); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (1)"); + assert results.contains("XVX Robot"); + } + + @Test + public void testJustExit() { + String bucket = "blue"; + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + HelloAccumulator.AccumulatorWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + WorkflowClient.start(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + + workflow.exit(); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (0)"); + assert !results.contains("Robot"); + } + + @Test + public void testNoExit() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + HelloAccumulator.AccumulatorWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + WorkflowClient.start(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + + Greeting xvxGreeting = new Greeting("XVX Robot", bucket, "1123581321"); + + workflow.sendGreeting(xvxGreeting); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (1)"); + assert results.contains("XVX Robot"); + } + + @Test + public void testMultipleGreetings() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + HelloAccumulator.AccumulatorWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + WorkflowClient.start(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + + workflow.sendGreeting(new Greeting("XVX Robot", bucket, "1123581321")); + workflow.sendGreeting(new Greeting("Han Robot", bucket, "112358")); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (2)"); + assert results.contains("XVX Robot"); + assert results.contains("Han Robot"); + } + + @Test + public void testDuplicateGreetings() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + HelloAccumulator.AccumulatorWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + WorkflowClient.start(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + + workflow.sendGreeting(new Greeting("XVX Robot", bucket, "1123581321")); + workflow.sendGreeting(new Greeting("Han Robot", bucket, "1123581321")); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (1)"); + assert results.contains("XVX Robot"); + assert !results.contains("Han Robot"); + } + + @Test + public void testWrongBucketGreeting() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + HelloAccumulator.AccumulatorWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + WorkflowClient.start(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + + workflow.sendGreeting(new Greeting("Bad Robot", "orange", "1123581321")); + workflow.sendGreeting(new Greeting("XVX Robot", bucket, "11235")); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (1)"); + assert results.contains("XVX Robot"); + assert !results.contains("Bad Robot"); + } + + @Test + public void testSignalWithStart() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + WorkflowClient client = testWorkflowRule.getWorkflowClient(); + HelloAccumulator.AccumulatorWorkflow workflow = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + Greeting starterGreeting = new Greeting("Robby Robot", bucket, "112"); + BatchRequest request = client.newSignalWithStartRequest(); + request.add(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow::sendGreeting, starterGreeting); + client.signalWithStart(request); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (1)"); + assert results.contains("Robby Robot"); + } + + @Test + public void testWaitTooLongForFirstWorkflow() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + WorkflowClient client = testWorkflowRule.getWorkflowClient(); + HelloAccumulator.AccumulatorWorkflow workflow = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(bucket) + .setWorkflowId("helloacc-blue") + .build()); + + Greeting starterGreeting = new Greeting("Robby Robot", bucket, "112"); + BatchRequest request = client.newSignalWithStartRequest(); + request.add(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow::sendGreeting, starterGreeting); + client.signalWithStart(request); + + // testEnv.sleep(MAX_AWAIT_TIME.plus(Duration.ofMillis(1))); is not long enough + // to guarantee the + // first workflow will end + testEnv.sleep(MAX_AWAIT_TIME.plus(Duration.ofMillis(100))); + + HelloAccumulator.AccumulatorWorkflow workflow2 = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(bucket) + .setWorkflowId("helloacc-blue") + .build()); + + Greeting secondGreeting = new Greeting("Dave Robot", bucket, "1123"); + + request = client.newSignalWithStartRequest(); + request.add(workflow2::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow2::sendGreeting, secondGreeting); + client.signalWithStart(request); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (1)"); + assert !results.contains("Robby Robot"); + assert results.contains("Dave Robot"); + } + + @Test + public void testWaitNotLongEnoughForNewWorkflow() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + WorkflowClient client = testWorkflowRule.getWorkflowClient(); + HelloAccumulator.AccumulatorWorkflow workflow = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(bucket) + .setWorkflowId("helloacc-blue") + .build()); + + Greeting starterGreeting = new Greeting("Robby Robot", bucket, "112"); + BatchRequest request = client.newSignalWithStartRequest(); + request.add(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow::sendGreeting, starterGreeting); + client.signalWithStart(request); + + testEnv.sleep(MAX_AWAIT_TIME.minus(Duration.ofMillis(1))); + + HelloAccumulator.AccumulatorWorkflow workflow2 = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(bucket) + .setWorkflowId("helloacc-blue") + .build()); + + Greeting secondGreeting = new Greeting("Dave Robot", bucket, "1123"); + + request = client.newSignalWithStartRequest(); + request.add(workflow2::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow2::sendGreeting, secondGreeting); + client.signalWithStart(request); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (2)"); + assert results.contains("Robby Robot"); + assert results.contains("Dave Robot"); + } + + @Test + public void testWaitExactlyMAX_TIME() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + WorkflowClient client = testWorkflowRule.getWorkflowClient(); + HelloAccumulator.AccumulatorWorkflow workflow = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(bucket) + .setWorkflowId("helloacc-blue") + .build()); + + Greeting starterGreeting = new Greeting("Robby Robot", bucket, "112"); + BatchRequest request = client.newSignalWithStartRequest(); + request.add(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow::sendGreeting, starterGreeting); + client.signalWithStart(request); + + testEnv.sleep(MAX_AWAIT_TIME); + + HelloAccumulator.AccumulatorWorkflow workflow2 = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(bucket) + .setWorkflowId("helloacc-blue") + .build()); + + Greeting secondGreeting = new Greeting("Dave Robot", bucket, "1123"); + + request = client.newSignalWithStartRequest(); + request.add(workflow2::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow2::sendGreeting, secondGreeting); + client.signalWithStart(request); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (2)"); + assert results.contains("Robby Robot"); + assert results.contains("Dave Robot"); + } + + @Test + public void testSignalAfterExit() { + String bucket = "blue"; + + ArrayDeque greetingList = new ArrayDeque(); + HashSet allGreetingsSet = new HashSet(); + testEnv = testWorkflowRule.getTestEnvironment(); + testEnv.start(); + + WorkflowClient client = testWorkflowRule.getWorkflowClient(); + HelloAccumulator.AccumulatorWorkflow workflow = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(bucket) + .setWorkflowId("helloacc-blue") + .build()); + + Greeting starterGreeting = new Greeting("Robby Robot", bucket, "112"); + BatchRequest request = client.newSignalWithStartRequest(); + request.add(workflow::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow::sendGreeting, starterGreeting); + client.signalWithStart(request); + + HelloAccumulator.AccumulatorWorkflow workflow2 = + client.newWorkflowStub( + HelloAccumulator.AccumulatorWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(bucket) + .setWorkflowId("helloacc-blue") + .build()); + + Greeting secondGreeting = new Greeting("Dave Robot", bucket, "1123"); + + request = client.newSignalWithStartRequest(); + request.add(workflow2::accumulateGreetings, bucket, greetingList, allGreetingsSet); + request.add(workflow2::sendGreeting, secondGreeting); + + // exit signal the workflow we signaled-to-start + workflow.exit(); + + // try to signal with start the workflow + client.signalWithStart(request); + + String results = workflow.accumulateGreetings(bucket, greetingList, allGreetingsSet); + assert results.contains("Hello (2)"); + assert results.contains("Robby Robot"); + assert results.contains("Dave Robot"); + } +} From 520d62c1097c2e63ca5d13ff12d80a8bd024a840 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jul 2024 21:54:23 -0400 Subject: [PATCH 178/240] Bump org.junit:junit-bom from 5.10.2 to 5.10.3 (#640) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.10.2 to 5.10.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.2...r5.10.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 22a5fa4f8..4a7508a82 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -39,7 +39,7 @@ dependencies { testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:5.12.0" - testImplementation(platform("org.junit:junit-bom:5.10.2")) + testImplementation(platform("org.junit:junit-bom:5.10.3")) testImplementation "org.junit.jupiter:junit-jupiter-api" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" testRuntimeOnly "org.junit.vintage:junit-vintage-engine" From 6f8c157346645a023dd4a6f75236c7a1ba9f8f52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jul 2024 21:55:06 -0400 Subject: [PATCH 179/240] Bump io.cloudevents:cloudevents-api from 3.0.0 to 4.0.1 (#642) Bumps [io.cloudevents:cloudevents-api](https://github.com/cloudevents/sdk-java) from 3.0.0 to 4.0.1. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/3.0.0...v4.0.1) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-api dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 4a7508a82..7eff8244c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -25,7 +25,7 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '3.0.0' - implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '3.0.0' + implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '4.0.1' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '3.0.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.5.Final' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.5.Final' From 768456e8056c9c03aa0641ad9707ba9f97107a91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jul 2024 21:55:31 -0400 Subject: [PATCH 180/240] Bump com.fasterxml.jackson:jackson-bom from 2.17.1 to 2.17.2 (#643) Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.17.1 to 2.17.2. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.17.1...jackson-bom-2.17.2) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 7eff8244c..f80f01087 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,7 @@ dependencies { testImplementation("io.temporal:temporal-testing:$javaSDKVersion") // Needed for SDK related functionality - implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.1")) + implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.2")) implementation "com.fasterxml.jackson.core:jackson-databind" implementation "com.fasterxml.jackson.core:jackson-core" From 2cf8aa4385be0f75b58a7bf4d32f675199bcfde1 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Sat, 13 Jul 2024 18:56:21 -0700 Subject: [PATCH 181/240] Update Java SDK to v1.24.1 (#645) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ee7a9a661..a4a6c7142 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.24.0' + javaSDKVersion = '1.24.1' camelVersion = '3.22.1' jarVersion = '1.0.0' } From a0c4395751f12682325d87f57be787b3a575a21e Mon Sep 17 00:00:00 2001 From: deepika-awasthi Date: Sat, 13 Jul 2024 18:57:43 -0700 Subject: [PATCH 182/240] fixing url for prometheus metrics endpoint in sysout (#646) --- .../main/java/io/temporal/samples/metrics/MetricsStarter.java | 2 +- .../main/java/io/temporal/samples/metrics/MetricsWorker.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java index 4989e765e..489463d31 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java @@ -72,7 +72,7 @@ public static void main(String[] args) { System.out.println("Result: " + result); - System.out.println("Starter metrics are available at http://localhost:8081/prometheus"); + System.out.println("Starter metrics are available at http://localhost:8078/metrics"); // We don't shut down the process here so metrics can be viewed. } diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java index 609e60abb..eced332dd 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java @@ -74,6 +74,6 @@ public static void main(String[] args) { factory.start(); - System.out.println("Workers metrics are available at http://localhost:8080/prometheus"); + System.out.println("Workers metrics are available at http://localhost:8077/metrics"); } } From 2516af4a3da87f9ce8e2d083a700125a9e8592cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 14 Jul 2024 02:04:15 +0000 Subject: [PATCH 183/240] Bump io.cloudevents:cloudevents-core from 3.0.0 to 4.0.1 (#644) Bumps [io.cloudevents:cloudevents-core](https://github.com/cloudevents/sdk-java) from 3.0.0 to 4.0.1. - [Release notes](https://github.com/cloudevents/sdk-java/releases) - [Commits](https://github.com/cloudevents/sdk-java/compare/3.0.0...v4.0.1) --- updated-dependencies: - dependency-name: io.cloudevents:cloudevents-core dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index f80f01087..75bb1346f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -24,7 +24,7 @@ dependencies { // Used in samples implementation group: 'commons-configuration', name: 'commons-configuration', version: '1.10' - implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '3.0.0' + implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '4.0.1' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '4.0.1' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '3.0.0' implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.5.Final' From 043e1c8e7c26e7b20d19b8d95ed5f877ee778545 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Wed, 17 Jul 2024 00:31:30 -0400 Subject: [PATCH 184/240] =?UTF-8?q?Add=20polling=20sample=20for=20infreque?= =?UTF-8?q?nt=20poll=20with=20Retry-After=20delay=20-=20showc=E2=80=A6=20(?= =?UTF-8?q?#649)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add polling sample for infrequent poll with Retry-After delay - showcases ApplicationFailure.newFailureWithCauseAndDelay Signed-off-by: Tihomir Surdilovic * fix formatting issue Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- .../temporal/samples/polling/TestService.java | 29 ++++++++- ...uentPollingWithRetryAfterActivityImpl.java | 63 +++++++++++++++++++ ...nfrequentPollingWithRetryAfterStarter.java | 61 ++++++++++++++++++ ...uentPollingWithRetryAfterWorkflowImpl.java | 57 +++++++++++++++++ .../infrequentwithretryafter/README.md | 47 ++++++++++++++ 5 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java create mode 100644 core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java create mode 100644 core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/README.md diff --git a/core/src/main/java/io/temporal/samples/polling/TestService.java b/core/src/main/java/io/temporal/samples/polling/TestService.java index eae382b17..829bfc9d4 100644 --- a/core/src/main/java/io/temporal/samples/polling/TestService.java +++ b/core/src/main/java/io/temporal/samples/polling/TestService.java @@ -19,6 +19,8 @@ package io.temporal.samples.polling; +import java.util.concurrent.ThreadLocalRandom; + /** * Test service that we want to poll. It simulates a service being down and then returning a result * after 5 attempts @@ -26,6 +28,9 @@ public class TestService { private int tryAttempt = 0; private int errorAttempts = 5; // default to 5 attempts before returning result + private boolean doRetryAfter = false; + private int minRetryAfter = 1; + private int maxRetryAfter = 3; public TestService() {} @@ -33,18 +38,40 @@ public TestService(int errorAttempts) { this.errorAttempts = errorAttempts; } + public TestService(int errorAttempts, boolean doRetryAfter) { + this.errorAttempts = errorAttempts; + this.doRetryAfter = doRetryAfter; + } + public String getServiceResult() throws TestServiceException { tryAttempt++; if (tryAttempt % errorAttempts == 0) { return "OK"; } else { - throw new TestServiceException("Service is down"); + if (!doRetryAfter) { + throw new TestServiceException("Service is down"); + } else { + throw new TestServiceException( + "Service is down", + ThreadLocalRandom.current().nextInt(minRetryAfter, maxRetryAfter + 1)); + } } } public static class TestServiceException extends Exception { + private int retryAfterInMinutes = 1; + public TestServiceException(String message) { super(message); } + + public TestServiceException(String message, int retryAfterInMinutes) { + super(message); + this.retryAfterInMinutes = retryAfterInMinutes; + } + + public int getRetryAfterInMinutes() { + return retryAfterInMinutes; + } } } diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java new file mode 100644 index 000000000..41cbba1f2 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.polling.infrequentwithretryafter; + +import io.temporal.activity.Activity; +import io.temporal.failure.ApplicationFailure; +import io.temporal.samples.polling.PollingActivities; +import io.temporal.samples.polling.TestService; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; + +public class InfrequentPollingWithRetryAfterActivityImpl implements PollingActivities { + private TestService service; + final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME; + + public InfrequentPollingWithRetryAfterActivityImpl(TestService service) { + this.service = service; + } + + @Override + public String doPoll() { + System.out.println( + "Attempt: " + + Activity.getExecutionContext().getInfo().getAttempt() + + " Poll time: " + + LocalDateTime.now(ZoneId.systemDefault()).format(ISO_FORMATTER)); + + try { + return service.getServiceResult(); + } catch (TestService.TestServiceException e) { + // we throw application failure that includes cause + // which is the test service exception + // and delay which is the interval to next retry based on test service retry-after directive + System.out.println("Activity next retry in: " + e.getRetryAfterInMinutes() + " minutes"); + throw ApplicationFailure.newFailureWithCauseAndDelay( + e.getMessage(), + e.getClass().getName(), + e, + // here we set the next retry interval based on Retry-After duration given to us by our + // service + Duration.ofMinutes(e.getRetryAfterInMinutes())); + } + } +} diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java new file mode 100644 index 000000000..ff8d0dd73 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.polling.infrequentwithretryafter; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.polling.PollingWorkflow; +import io.temporal.samples.polling.TestService; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class InfrequentPollingWithRetryAfterStarter { + private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + private static final WorkflowClient client = WorkflowClient.newInstance(service); + private static final String taskQueue = "pollingSampleQueue"; + private static final String workflowId = "InfrequentPollingWithRetryAfterWorkflow"; + + public static void main(String[] args) { + // Create our worker and register workflow and activities + createWorker(); + + // Create typed workflow stub and start execution (sync, wait for results) + PollingWorkflow workflow = + client.newWorkflowStub( + PollingWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(taskQueue).setWorkflowId(workflowId).build()); + String result = workflow.exec(); + System.out.println("Result: " + result); + System.exit(0); + } + + private static void createWorker() { + WorkerFactory workerFactory = WorkerFactory.newInstance(client); + Worker worker = workerFactory.newWorker(taskQueue); + + // Register workflow and activities + worker.registerWorkflowImplementationTypes(InfrequentPollingWithRetryAfterWorkflowImpl.class); + worker.registerActivitiesImplementations( + new InfrequentPollingWithRetryAfterActivityImpl(new TestService(4, true))); + + workerFactory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterWorkflowImpl.java new file mode 100644 index 000000000..96ff76968 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterWorkflowImpl.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.polling.infrequentwithretryafter; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.RetryOptions; +import io.temporal.samples.polling.PollingActivities; +import io.temporal.samples.polling.PollingWorkflow; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class InfrequentPollingWithRetryAfterWorkflowImpl implements PollingWorkflow { + @Override + public String exec() { + /* + * Infrequent polling via activity can be implemented via activity retries. For this sample we + * want to poll the test service initially 60 seconds. After that we want to retry it based on + * the Retry-After directive from the downstream servie we are invoking from the activity. + * + *

    + *
  1. Set RetryPolicy backoff coefficient of 1 + *
  2. Set initial interval to the poll frequency (since coefficient is 1, same interval will + * be used as default retry attempt) + *
+ */ + ActivityOptions options = + ActivityOptions.newBuilder() + // Set activity StartToClose timeout (single activity exec), does not include retries + .setStartToCloseTimeout(Duration.ofSeconds(2)) + .setRetryOptions( + RetryOptions.newBuilder() + .setBackoffCoefficient(1) + // note we don't set initial interval here + .build()) + .build(); + // create our activities stub and start activity execution + PollingActivities activities = Workflow.newActivityStub(PollingActivities.class, options); + return activities.doPoll(); + } +} diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/README.md b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/README.md new file mode 100644 index 000000000..bb58a7508 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/README.md @@ -0,0 +1,47 @@ +## Infrequent polling with Service returning Retry-After time + +* Note - for this sample to work you should use Temporal Service +version 1.24.2 or Temporal Cloud + +* Note - for sample we assume that our downstream service returns a retry-after duration +that is longer than 1 minute + +This sample shows how we can use Activity retries for infrequent polling of a third-party service (for example via REST). +This method can be used for infrequent polls of one minute or slower. +For this sample our test service also returns a Retry-After time (typically its done via response header but +for sample its just done in service exception) + +We utilize activity retries for this option, setting Retries options: +* setBackoffCoefficient to 1 +* here we do not set initial interval as its changed by the Retry-After duration +sent to us by the downstream service our activity invokes +* +This will allow us to retry our Activity based on the Retry-After duration our downstream service +tells us. + +To run this sample: +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.polling.infrequent.InfrequentPollingWithRetryAfterStarter +``` + +Since our test service simulates it being "down" for 3 polling attempts and then returns "OK" on the 4th poll attempt, +our Workflow is going to perform 3 activity retries +with different intervals based on the Retry-After time our serviec gives us, +and then return the service result on the successful 4th attempt. + +Note that individual Activity retries are not recorded in +Workflow History, so we this approach we can poll for a very long time without affecting the history size. + +### Sample result +If you run this sample you can see following in the logs for example: + +``` +Attempt: 1 Poll time: 2024-07-14T22:03:03.750506 +Activity next retry in: 2 minutes +Attempt: 2 Poll time: 2024-07-14T22:05:03.780079 +Activity next retry in: 3 minutes +Attempt: 3 Poll time: 2024-07-14T22:08:03.799703 +Activity next retry in: 1 minutes +Attempt: 4 Poll time: 2024-07-14T22:09:03.817751 +Result: OK +``` \ No newline at end of file From dd0075d84b32283b685d4a1417260c8b0c173039 Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Wed, 17 Jul 2024 21:39:22 +0200 Subject: [PATCH 185/240] Refactored SAGA sample and added Synchronous SAGA sample. (#647) * Refactored bookingsaga * Added bookingsyncsaga --- README.md | 2 + .../temporal/samples/bookingsaga/Booking.java | 62 +++++++++++ .../io/temporal/samples/bookingsaga/README.md | 9 +- .../bookingsaga/TripBookingActivities.java | 21 ++-- .../TripBookingActivitiesImpl.java | 29 ++--- .../bookingsaga/TripBookingClient.java | 48 +++++++++ ...ookingSaga.java => TripBookingWorker.java} | 25 +---- .../bookingsaga/TripBookingWorkflow.java | 2 +- .../bookingsaga/TripBookingWorkflowImpl.java | 32 +++--- .../samples/bookingsyncsaga/Booking.java | 59 +++++++++++ .../samples/bookingsyncsaga/README.md | 18 ++++ .../TripBookingActivities.java | 80 ++++++++++++++ .../TripBookingActivitiesImpl.java | 74 +++++++++++++ .../bookingsyncsaga/TripBookingClient.java | 51 +++++++++ .../bookingsyncsaga/TripBookingWorker.java | 55 ++++++++++ .../bookingsyncsaga/TripBookingWorkflow.java | 39 +++++++ .../TripBookingWorkflowImpl.java | 98 +++++++++++++++++ .../bookingsaga/TripBookingWorkflowTest.java | 100 ++++++++---------- .../TripBookingWorkflowTest.java} | 60 ++++++++--- 19 files changed, 734 insertions(+), 130 deletions(-) create mode 100644 core/src/main/java/io/temporal/samples/bookingsaga/Booking.java create mode 100644 core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java rename core/src/main/java/io/temporal/samples/bookingsaga/{TripBookingSaga.java => TripBookingWorker.java} (75%) create mode 100644 core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java create mode 100644 core/src/main/java/io/temporal/samples/bookingsyncsaga/README.md create mode 100644 core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivities.java create mode 100644 core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java create mode 100644 core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java create mode 100644 core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowImpl.java rename core/src/test/java/io/temporal/samples/{bookingsaga/TripBookingWorkflowJUnit5Test.java => bookingsyncsaga/TripBookingWorkflowTest.java} (53%) diff --git a/README.md b/README.md index 216496b2c..323d71c01 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Booking SAGA**](/core/src/main/java/io/temporal/samples/bookingsaga): Demonstrates Temporals take on the Camunda BPMN "trip booking" example. +- [**Synchronous Booking SAGA**](/core/src/main/java/io/temporal/samples/bookingsyncsaga): Demonstrates low latency SAGA with potentially long compensations. + - [**Money Transfer**](/core/src/main/java/io/temporal/samples/moneytransfer): Demonstrates the use of a dedicated Activity Worker. - [**Money Batch**](/core/src/main/java/io/temporal/samples/moneybatch): Demonstrates a situation where a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. This sample can be easily extended to perform a payment based on more complex criteria, such as at a specific time or an accumulated amount. The sample also demonstrates how to Signal the Workflow when it executes (*Signal with start*). If the Workflow is already executing, it just receives the Signal. If it is not executing, then the Workflow executes first, and then the Signal is delivered to it. *Signal with start* is a "lazy" way to execute Workflows when Signaling them. diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/Booking.java b/core/src/main/java/io/temporal/samples/bookingsaga/Booking.java new file mode 100644 index 000000000..3b9eb73ff --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsaga/Booking.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsaga; + +public final class Booking { + private String carReservationID; + private String hotelReservationID; + private String flightReservationID; + + /** Empty constructor to keep Jackson serializer happy. */ + public Booking() {} + + public Booking(String carReservationID, String hotelReservationID, String flightReservationID) { + this.carReservationID = carReservationID; + this.hotelReservationID = hotelReservationID; + this.flightReservationID = flightReservationID; + } + + public String getCarReservationID() { + return carReservationID; + } + + public String getHotelReservationID() { + return hotelReservationID; + } + + public String getFlightReservationID() { + return flightReservationID; + } + + @Override + public String toString() { + return "Booking{" + + "carReservationID='" + + carReservationID + + '\'' + + ", hotelReservationID='" + + hotelReservationID + + '\'' + + ", flightReservationID='" + + flightReservationID + + '\'' + + '}'; + } +} diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/README.md b/core/src/main/java/io/temporal/samples/bookingsaga/README.md index d15e563a8..f3783ec0c 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/README.md +++ b/core/src/main/java/io/temporal/samples/bookingsaga/README.md @@ -1,6 +1,8 @@ ## Saga example: trip booking -Temporal implementation of the [Camunda BPMN trip booking example](https://github.com/berndruecker/trip-booking-saga-java) which demonstrates Temporal approach to SAGA. +Temporal implementation of +the [Camunda BPMN trip booking example](https://github.com/berndruecker/trip-booking-saga-java) which demonstrates +Temporal approach to SAGA. Run the following command to start the sample: @@ -8,4 +10,7 @@ Run the following command to start the sample: ./gradlew -q execute -PmainClass=io.temporal.samples.bookingsaga.TripBookingSaga ``` -Sample unit testing: [TripBookingWorkflowTest](https://github.com/temporalio/samples-java/blob/main/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java) +Note that the booking is expected to fail to demonstrate the compensation flow. + +Sample unit +testing: [TripBookingWorkflowTest](https://github.com/temporalio/samples-java/blob/main/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java) diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java index ce02c963d..b8e8db77f 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java @@ -27,51 +27,54 @@ public interface TripBookingActivities { /** * Request a car rental reservation. * + * @param requestId used for idempotency and compensation correlation. * @param name customer name * @return reservationID */ - String reserveCar(String name); + String reserveCar(String requestId, String name); /** * Request a flight reservation. * + * @param requestId used for idempotency and compensation correlation. * @param name customer name * @return reservationID */ - String bookFlight(String name); + String bookFlight(String requestId, String name); /** * Request a hotel reservation. * + * @param requestId used for idempotency and compensation correlation. * @param name customer name * @return reservationID */ - String bookHotel(String name); + String bookHotel(String requestId, String name); /** * Cancel a flight reservation. * * @param name customer name - * @param reservationID id returned by bookFlight + * @param requestId the same id is passed to bookFlight * @return cancellationConfirmationID */ - String cancelFlight(String reservationID, String name); + String cancelFlight(String requestId, String name); /** * Cancel a hotel reservation. * * @param name customer name - * @param reservationID id returned by bookHotel + * @param requestId the same id is passed to bookHotel * @return cancellationConfirmationID */ - String cancelHotel(String reservationID, String name); + String cancelHotel(String requestId, String name); /** * Cancel a car rental reservation. * * @param name customer name - * @param reservationID id returned by reserveCar + * @param requestId the same id is passed to reserveCar * @return cancellationConfirmationID */ - String cancelCar(String reservationID, String name); + String cancelCar(String requestId, String name); } diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java index b1beb61e7..5fbfd91bd 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java @@ -19,42 +19,45 @@ package io.temporal.samples.bookingsaga; +import io.temporal.failure.ApplicationFailure; import java.util.UUID; public class TripBookingActivitiesImpl implements TripBookingActivities { @Override - public String reserveCar(String name) { - System.out.println("reserve car for '" + name + "'"); + public String reserveCar(String requestId, String name) { + System.out.println("reserving car for request '" + requestId + "` and name `" + name + "'"); return UUID.randomUUID().toString(); } @Override - public String bookFlight(String name) { - System.out.println("failing to book flight for '" + name + "'"); - throw new RuntimeException("Flight booking did not work"); + public String bookFlight(String requestId, String name) { + System.out.println( + "failing to book flight for request '" + requestId + "' and name '" + name + "'"); + throw ApplicationFailure.newNonRetryableFailure( + "Flight booking did not work", "bookingFailure"); } @Override - public String bookHotel(String name) { - System.out.println("booking hotel for '" + name + "'"); + public String bookHotel(String requestId, String name) { + System.out.println("booking hotel for request '" + requestId + "` and name `" + name + "'"); return UUID.randomUUID().toString(); } @Override - public String cancelFlight(String reservationID, String name) { - System.out.println("cancelling flight reservation '" + reservationID + "' for '" + name + "'"); + public String cancelFlight(String requestId, String name) { + System.out.println("cancelling flight reservation '" + requestId + "' for '" + name + "'"); return UUID.randomUUID().toString(); } @Override - public String cancelHotel(String reservationID, String name) { - System.out.println("cancelling hotel reservation '" + reservationID + "' for '" + name + "'"); + public String cancelHotel(String requestId, String name) { + System.out.println("cancelling hotel reservation '" + requestId + "' for '" + name + "'"); return UUID.randomUUID().toString(); } @Override - public String cancelCar(String reservationID, String name) { - System.out.println("cancelling car reservation '" + reservationID + "' for '" + name + "'"); + public String cancelCar(String requestId, String name) { + System.out.println("cancelling car reservation '" + requestId + "' for '" + name + "'"); return UUID.randomUUID().toString(); } } diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java new file mode 100644 index 000000000..075eaa718 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsaga; + +import com.google.common.base.Throwables; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; + +public class TripBookingClient { + + static final String TASK_QUEUE = "TripBooking"; + + public static void main(String[] args) { + // gRPC stubs wrapper that talks to the local docker instance of temporal service. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // client that can be used to start and signal workflows + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkflowOptions options = + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId("Booking1").build(); + TripBookingWorkflow trip = client.newWorkflowStub(TripBookingWorkflow.class, options); + try { + Booking booking = trip.bookTrip("trip1"); + System.out.println("Booking: " + booking); + } catch (Exception e) { + System.out.println(Throwables.getStackTraceAsString(e)); + } + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingSaga.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java similarity index 75% rename from core/src/main/java/io/temporal/samples/bookingsaga/TripBookingSaga.java rename to core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java index 4c324c54f..d0dd532d6 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingSaga.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java @@ -20,13 +20,14 @@ package io.temporal.samples.bookingsaga; import io.temporal.client.WorkflowClient; -import io.temporal.client.WorkflowException; -import io.temporal.client.WorkflowOptions; +import io.temporal.samples.bookingsyncsaga.TripBookingActivities; +import io.temporal.samples.bookingsyncsaga.TripBookingActivitiesImpl; +import io.temporal.samples.bookingsyncsaga.TripBookingWorkflowImpl; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; -public class TripBookingSaga { +public class TripBookingWorker { static final String TASK_QUEUE = "TripBooking"; @@ -53,23 +54,5 @@ public static void main(String[] args) { // Start all workers created by this factory. factory.start(); System.out.println("Worker started for task queue: " + TASK_QUEUE); - - // now we can start running instances of our saga - its state will be persisted - WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build(); - TripBookingWorkflow trip1 = client.newWorkflowStub(TripBookingWorkflow.class, options); - try { - trip1.bookTrip("trip1"); - } catch (WorkflowException e) { - // Expected - } - - try { - TripBookingWorkflow trip2 = client.newWorkflowStub(TripBookingWorkflow.class, options); - trip2.bookTrip("trip2"); - } catch (WorkflowException e) { - // Expected - } - - System.exit(0); } } diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java index 4431cd505..e9ec8f10e 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java @@ -25,5 +25,5 @@ @WorkflowInterface public interface TripBookingWorkflow { @WorkflowMethod - void bookTrip(String name); + Booking bookTrip(String name); } diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java index f7caddaac..b4558ed4a 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java @@ -20,7 +20,6 @@ package io.temporal.samples.bookingsaga; import io.temporal.activity.ActivityOptions; -import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.workflow.Saga; import io.temporal.workflow.Workflow; @@ -29,30 +28,35 @@ public class TripBookingWorkflowImpl implements TripBookingWorkflow { private final ActivityOptions options = - ActivityOptions.newBuilder() - .setStartToCloseTimeout(Duration.ofHours(1)) - // disable retries for example to run faster - .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) - .build(); + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build(); private final TripBookingActivities activities = Workflow.newActivityStub(TripBookingActivities.class, options); @Override - public void bookTrip(String name) { + public Booking bookTrip(String name) { // Configure SAGA to run compensation activities in parallel Saga.Options sagaOptions = new Saga.Options.Builder().setParallelCompensation(true).build(); Saga saga = new Saga(sagaOptions); try { - String carReservationID = activities.reserveCar(name); - saga.addCompensation(activities::cancelCar, carReservationID, name); + // addCompensation is added before the actual call to handle situations when the call failed + // due to a timeout and its success is not clear. + // The compensation code must handle situations when the actual function wasn't executed + // gracefully. + String carReservationRequestId = Workflow.randomUUID().toString(); + saga.addCompensation(activities::cancelCar, carReservationRequestId, name); + String carReservationID = activities.reserveCar(carReservationRequestId, name); - String hotelReservationID = activities.bookHotel(name); - saga.addCompensation(activities::cancelHotel, hotelReservationID, name); + String hotelReservationRequestID = Workflow.randomUUID().toString(); + saga.addCompensation(activities::cancelHotel, hotelReservationRequestID, name); + String hotelReservationId = activities.bookHotel(hotelReservationRequestID, name); - String flightReservationID = activities.bookFlight(name); - saga.addCompensation(activities::cancelFlight, flightReservationID, name); + String flightReservationRequestID = Workflow.randomUUID().toString(); + saga.addCompensation(activities::cancelFlight, flightReservationRequestID, name); + String flightReservationID = activities.bookFlight(flightReservationRequestID, name); + return new Booking(carReservationID, hotelReservationId, flightReservationID); } catch (ActivityFailure e) { - saga.compensate(); + // Ensure that compensations are executed even if the workflow is canceled. + Workflow.newDetachedCancellationScope(() -> saga.compensate()).run(); throw e; } } diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java new file mode 100644 index 000000000..a6a0a4e28 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsyncsaga; + +public final class Booking { + private final String carReservationID; + private final String hotelReservationID; + private final String flightReservationID; + + public Booking(String carReservationID, String hotelReservationID, String flightReservationID) { + this.carReservationID = carReservationID; + this.hotelReservationID = hotelReservationID; + this.flightReservationID = flightReservationID; + } + + public String getCarReservationID() { + return carReservationID; + } + + public String getHotelReservationID() { + return hotelReservationID; + } + + public String getFlightReservationID() { + return flightReservationID; + } + + @Override + public String toString() { + return "Booking{" + + "carReservationID='" + + carReservationID + + '\'' + + ", hotelReservationID='" + + hotelReservationID + + '\'' + + ", flightReservationID='" + + flightReservationID + + '\'' + + '}'; + } +} diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/README.md b/core/src/main/java/io/temporal/samples/bookingsyncsaga/README.md new file mode 100644 index 000000000..b16408bcf --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/README.md @@ -0,0 +1,18 @@ +## Saga example: synchronous trip booking + +The sample demonstrates low latency workflow with client synchronously waiting for result using an update. +In case of failures the caller is unblocked and workflow continues executing compensations +for as long as needed. + +Run the following command to start the worker: + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.bookingsyncsaga.TripBookingWorker +``` + +Run the following command to request a booking. +Note that the booking is expected to fail to demonstrate the compensation flow. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.bookingsyncsaga.TripBookingClient +``` diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivities.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivities.java new file mode 100644 index 000000000..a826eb57e --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivities.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsyncsaga; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface TripBookingActivities { + + /** + * Request a car rental reservation. + * + * @param requestId used for idempotency and compensation correlation. + * @param name customer name + * @return reservationID + */ + String reserveCar(String requestId, String name); + + /** + * Request a flight reservation. + * + * @param requestId used for idempotency and compensation correlation. + * @param name customer name + * @return reservationID + */ + String bookFlight(String requestId, String name); + + /** + * Request a hotel reservation. + * + * @param requestId used for idempotency and compensation correlation. + * @param name customer name + * @return reservationID + */ + String bookHotel(String requestId, String name); + + /** + * Cancel a flight reservation. + * + * @param name customer name + * @param requestId the same id is passed to bookFlight + * @return cancellationConfirmationID + */ + String cancelFlight(String requestId, String name); + + /** + * Cancel a hotel reservation. + * + * @param name customer name + * @param requestId the same id is passed to bookHotel + * @return cancellationConfirmationID + */ + String cancelHotel(String requestId, String name); + + /** + * Cancel a car rental reservation. + * + * @param name customer name + * @param requestId the same id is passed to reserveCar + * @return cancellationConfirmationID + */ + String cancelCar(String requestId, String name); +} diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivitiesImpl.java new file mode 100644 index 000000000..bb0bc5de1 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivitiesImpl.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsyncsaga; + +import io.temporal.failure.ApplicationFailure; +import java.util.UUID; + +public class TripBookingActivitiesImpl implements TripBookingActivities { + @Override + public String reserveCar(String requestId, String name) { + System.out.println("reserving car for request '" + requestId + "` and name `" + name + "'"); + return UUID.randomUUID().toString(); + } + + @Override + public String bookFlight(String requestId, String name) { + System.out.println( + "failing to book flight for request '" + requestId + "' and name '" + name + "'"); + throw ApplicationFailure.newNonRetryableFailure( + "Flight booking did not work", "bookingFailure"); + } + + @Override + public String bookHotel(String requestId, String name) { + System.out.println("booking hotel for request '" + requestId + "` and name `" + name + "'"); + return UUID.randomUUID().toString(); + } + + @Override + public String cancelFlight(String requestId, String name) { + System.out.println("cancelling flight reservation '" + requestId + "' for '" + name + "'"); + sleep(1000); + return UUID.randomUUID().toString(); + } + + @Override + public String cancelHotel(String requestId, String name) { + System.out.println("cancelling hotel reservation '" + requestId + "' for '" + name + "'"); + sleep(1000); + return UUID.randomUUID().toString(); + } + + @Override + public String cancelCar(String requestId, String name) { + System.out.println("cancelling car reservation '" + requestId + "' for '" + name + "'"); + sleep(1000); + return UUID.randomUUID().toString(); + } + + private static void sleep(long milliseconds) { + try { + Thread.sleep(milliseconds); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java new file mode 100644 index 000000000..e4857c4ea --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsyncsaga; + +import com.google.common.base.Throwables; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; + +public class TripBookingClient { + + static final String TASK_QUEUE = "TripBookingSync"; + + public static void main(String[] args) { + // gRPC stubs wrapper that talks to the local docker instance of temporal service. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // client that can be used to start and signal workflows + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkflowOptions options = + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId("Booking1").build(); + TripBookingWorkflow trip1 = client.newWorkflowStub(TripBookingWorkflow.class, options); + // Start workflow asynchronously + WorkflowClient.start(trip1::bookTrip, "trip1"); + try { + // Wait for workflow to complete or fail the booking using an update. + Booking booking = trip1.waitForBooking(); + System.out.println("Booking: " + booking); + } catch (Exception e) { + System.out.println(Throwables.getStackTraceAsString(e)); + } + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java new file mode 100644 index 000000000..035c1859e --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsyncsaga; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class TripBookingWorker { + + static final String TASK_QUEUE = "TripBooking"; + + @SuppressWarnings("CatchAndPrintStackTrace") + public static void main(String[] args) { + // gRPC stubs wrapper that talks to the local docker instance of temporal service. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // client that can be used to start and signal workflows + WorkflowClient client = WorkflowClient.newInstance(service); + + // worker factory that can be used to create workers for specific task queues + WorkerFactory factory = WorkerFactory.newInstance(client); + + // Worker that listens on a task queue and hosts both workflow and activity implementations. + Worker worker = factory.newWorker(TASK_QUEUE); + + // Workflows are stateful. So you need a type to create instances. + worker.registerWorkflowImplementationTypes(TripBookingWorkflowImpl.class); + + // Activities are stateless and thread safe. So a shared instance is used. + TripBookingActivities tripBookingActivities = new TripBookingActivitiesImpl(); + worker.registerActivitiesImplementations(tripBookingActivities); + + // Start all workers created by this factory. + factory.start(); + System.out.println("Worker started for task queue: " + TASK_QUEUE); + } +} diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java new file mode 100644 index 000000000..99ab6bf79 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsyncsaga; + +import io.temporal.workflow.UpdateMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface TripBookingWorkflow { + @WorkflowMethod + void bookTrip(String name); + + /** + * Used to wait for booking completion or failure. After this method returns a failure workflow + * keeps running executing compensations. + * + * @return booking information. + */ + @UpdateMethod + Booking waitForBooking(); +} diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowImpl.java new file mode 100644 index 000000000..8f8c640cc --- /dev/null +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowImpl.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.bookingsyncsaga; + +import io.temporal.activity.ActivityOptions; +import io.temporal.activity.LocalActivityOptions; +import io.temporal.common.RetryOptions; +import io.temporal.failure.ActivityFailure; +import io.temporal.workflow.CompletablePromise; +import io.temporal.workflow.Saga; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class TripBookingWorkflowImpl implements TripBookingWorkflow { + + /** + * Use local activities for the happy path. This allows to execute the whole sequence as a single + * workflow task. Don't use local activities if you expect long retries. + */ + private final LocalActivityOptions options = + LocalActivityOptions.newBuilder() + .build() + .newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(1)) + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(3).build()) + .build(); + + private final TripBookingActivities activities = + Workflow.newLocalActivityStub(TripBookingActivities.class, options); + + /** Use normal activities for compensations, as they potentially need long retries. */ + private final ActivityOptions compensationOptions = + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofHours(1)) + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) + .build(); + + private final TripBookingActivities compensationActivities = + Workflow.newActivityStub(TripBookingActivities.class, compensationOptions); + + /** Used to pass result to the update function. */ + private final CompletablePromise booking = Workflow.newPromise(); + + @Override + public void bookTrip(String name) { + Saga.Options sagaOptions = new Saga.Options.Builder().build(); + Saga saga = new Saga(sagaOptions); + try { + // addCompensation is added before the actual call to handle situations when the call failed + // due to + // a timeout and its success is not clear. + // The compensation code must handle situations when the actual function wasn't executed + // gracefully. + String carReservationRequestId = Workflow.randomUUID().toString(); + saga.addCompensation(compensationActivities::cancelCar, carReservationRequestId, name); + String carReservationID = activities.reserveCar(carReservationRequestId, name); + + String hotelReservationRequestID = Workflow.randomUUID().toString(); + saga.addCompensation(compensationActivities::cancelHotel, hotelReservationRequestID, name); + String hotelReservationId = activities.bookHotel(hotelReservationRequestID, name); + + String flightReservationRequestID = Workflow.randomUUID().toString(); + saga.addCompensation(compensationActivities::cancelFlight, flightReservationRequestID, name); + String flightReservationID = activities.bookFlight(flightReservationRequestID, name); + + // Unblock the update function + booking.complete(new Booking(carReservationID, hotelReservationId, flightReservationID)); + } catch (ActivityFailure e) { + // Unblock the update function + booking.completeExceptionally(e); + // Ensure that compensations are executed even if the workflow is canceled. + Workflow.newDetachedCancellationScope(() -> saga.compensate()).run(); + throw e; + } + } + + @Override + public Booking waitForBooking() { + return booking.get(); + } +} diff --git a/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java b/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java index d66a25701..7a2d2cca6 100644 --- a/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java @@ -19,23 +19,27 @@ package io.temporal.samples.bookingsaga; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import io.temporal.client.WorkflowException; -import io.temporal.client.WorkflowOptions; import io.temporal.failure.ApplicationFailure; -import io.temporal.testing.TestWorkflowRule; -import org.junit.Rule; -import org.junit.Test; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.ArgumentCaptor; public class TripBookingWorkflowTest { - @Rule - public TestWorkflowRule testWorkflowRule = - TestWorkflowRule.newBuilder() + @RegisterExtension + public static final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() .setWorkflowTypes(TripBookingWorkflowImpl.class) .setDoNotStart(true) .build(); @@ -45,58 +49,48 @@ public class TripBookingWorkflowTest { * other tests on using mocked activities to test SAGA logic. */ @Test - public void testTripBookingFails() { - testWorkflowRule.getWorker().registerActivitiesImplementations(new TripBookingActivitiesImpl()); - testWorkflowRule.getTestEnvironment().start(); + public void testTripBookingFails( + TestWorkflowEnvironment testEnv, Worker worker, TripBookingWorkflow workflow) { + worker.registerActivitiesImplementations(new TripBookingActivitiesImpl()); + testEnv.start(); - TripBookingWorkflow workflow = - testWorkflowRule - .getWorkflowClient() - .newWorkflowStub( - TripBookingWorkflow.class, - WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); - try { - workflow.bookTrip("trip1"); - fail("unreachable"); - } catch (WorkflowException e) { - assertEquals( - "Flight booking did not work", - ((ApplicationFailure) e.getCause().getCause()).getOriginalMessage()); - } - - testWorkflowRule.getTestEnvironment().shutdown(); + WorkflowException exception = + assertThrows(WorkflowException.class, () -> workflow.bookTrip("trip1")); + assertEquals( + "Flight booking did not work", + ((ApplicationFailure) exception.getCause().getCause()).getOriginalMessage()); } /** Unit test workflow logic using mocked activities. */ @Test - public void testSAGA() { + public void testSAGA( + TestWorkflowEnvironment testEnv, Worker worker, TripBookingWorkflow workflow) { TripBookingActivities activities = mock(TripBookingActivities.class); - when(activities.bookHotel("trip1")).thenReturn("HotelBookingID1"); - when(activities.reserveCar("trip1")).thenReturn("CarBookingID1"); - when(activities.bookFlight("trip1")) - .thenThrow(new RuntimeException("Flight booking did not work")); - testWorkflowRule.getWorker().registerActivitiesImplementations(activities); - testWorkflowRule.getTestEnvironment().start(); + ArgumentCaptor captorHotelRequestId = ArgumentCaptor.forClass(String.class); + when(activities.bookHotel(captorHotelRequestId.capture(), eq("trip1"))) + .thenReturn("HotelBookingID1"); + + ArgumentCaptor captorCarRequestId = ArgumentCaptor.forClass(String.class); + when(activities.reserveCar(captorCarRequestId.capture(), eq("trip1"))) + .thenReturn("CarBookingID1"); - TripBookingWorkflow workflow = - testWorkflowRule - .getWorkflowClient() - .newWorkflowStub( - TripBookingWorkflow.class, - WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); - try { - workflow.bookTrip("trip1"); - fail("unreachable"); - } catch (WorkflowException e) { - assertEquals( - "Flight booking did not work", - ((ApplicationFailure) e.getCause().getCause()).getOriginalMessage()); - } + ArgumentCaptor captorFlightRequestId = ArgumentCaptor.forClass(String.class); + when(activities.bookFlight(captorFlightRequestId.capture(), eq("trip1"))) + .thenThrow( + ApplicationFailure.newNonRetryableFailure( + "Flight booking did not work", "bookingFailure")); + worker.registerActivitiesImplementations(activities); + testEnv.start(); - verify(activities).cancelHotel(eq("HotelBookingID1"), eq("trip1")); - verify(activities).cancelCar(eq("CarBookingID1"), eq("trip1")); + WorkflowException exception = + assertThrows(WorkflowException.class, () -> workflow.bookTrip("trip1")); + assertEquals( + "Flight booking did not work", + ((ApplicationFailure) exception.getCause().getCause()).getOriginalMessage()); - testWorkflowRule.getTestEnvironment().shutdown(); + verify(activities).cancelHotel(captorHotelRequestId.getValue(), "trip1"); + verify(activities).cancelCar(captorCarRequestId.getValue(), "trip1"); + verify(activities).cancelFlight(captorFlightRequestId.getValue(), "trip1"); } } diff --git a/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowJUnit5Test.java b/core/src/test/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowTest.java similarity index 53% rename from core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowJUnit5Test.java rename to core/src/test/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowTest.java index 7191ff60e..8a170c169 100644 --- a/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowJUnit5Test.java +++ b/core/src/test/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowTest.java @@ -17,23 +17,26 @@ * permissions and limitations under the License. */ -package io.temporal.samples.bookingsaga; +package io.temporal.samples.bookingsyncsaga; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; +import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowException; +import io.temporal.client.WorkflowStub; +import io.temporal.client.WorkflowUpdateException; import io.temporal.failure.ApplicationFailure; import io.temporal.testing.TestWorkflowEnvironment; import io.temporal.testing.TestWorkflowExtension; import io.temporal.worker.Worker; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.ArgumentCaptor; -public class TripBookingWorkflowJUnit5Test { +public class TripBookingWorkflowTest { @RegisterExtension public static final TestWorkflowExtension testWorkflowExtension = @@ -54,7 +57,7 @@ public void testTripBookingFails( WorkflowException exception = assertThrows(WorkflowException.class, () -> workflow.bookTrip("trip1")); - assertEquals( + Assertions.assertEquals( "Flight booking did not work", ((ApplicationFailure) exception.getCause().getCause()).getOriginalMessage()); } @@ -64,20 +67,43 @@ public void testTripBookingFails( public void testSAGA( TestWorkflowEnvironment testEnv, Worker worker, TripBookingWorkflow workflow) { TripBookingActivities activities = mock(TripBookingActivities.class); - when(activities.bookHotel("trip1")).thenReturn("HotelBookingID1"); - when(activities.reserveCar("trip1")).thenReturn("CarBookingID1"); - when(activities.bookFlight("trip1")) - .thenThrow(new RuntimeException("Flight booking did not work")); + + ArgumentCaptor captorHotelRequestId = ArgumentCaptor.forClass(String.class); + when(activities.bookHotel(captorHotelRequestId.capture(), eq("trip1"))) + .thenReturn("HotelBookingID1"); + + ArgumentCaptor captorCarRequestId = ArgumentCaptor.forClass(String.class); + when(activities.reserveCar(captorCarRequestId.capture(), eq("trip1"))) + .thenReturn("CarBookingID1"); + + ArgumentCaptor captorFlightRequestId = ArgumentCaptor.forClass(String.class); + when(activities.bookFlight(captorFlightRequestId.capture(), eq("trip1"))) + .thenThrow( + ApplicationFailure.newNonRetryableFailure( + "Flight booking did not work", "bookingFailure")); worker.registerActivitiesImplementations(activities); testEnv.start(); - WorkflowException exception = - assertThrows(WorkflowException.class, () -> workflow.bookTrip("trip1")); - assertEquals( + // Starts workflow asynchronously. + WorkflowClient.start(workflow::bookTrip, "trip1"); + + // Waits for update to return. + WorkflowException exception1 = + assertThrows(WorkflowUpdateException.class, () -> workflow.waitForBooking()); + Assertions.assertEquals( "Flight booking did not work", - ((ApplicationFailure) exception.getCause().getCause()).getOriginalMessage()); + ((ApplicationFailure) exception1.getCause().getCause()).getOriginalMessage()); + + // Waits for workflow to complete. + WorkflowStub stub = WorkflowStub.fromTyped(workflow); + WorkflowException exception2 = + assertThrows(WorkflowException.class, () -> stub.getResult(Void.class)); + Assertions.assertEquals( + "Flight booking did not work", + ((ApplicationFailure) exception2.getCause().getCause()).getOriginalMessage()); - verify(activities).cancelHotel("HotelBookingID1", "trip1"); - verify(activities).cancelCar("CarBookingID1", "trip1"); + verify(activities).cancelHotel(captorHotelRequestId.getValue(), "trip1"); + verify(activities).cancelCar(captorCarRequestId.getValue(), "trip1"); + verify(activities).cancelFlight(captorFlightRequestId.getValue(), "trip1"); } } From 637c2e66fd2dab43d9f3f39e5fd9c55e4f3884f0 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Sun, 21 Jul 2024 19:55:18 -0400 Subject: [PATCH 186/240] update dsl sample, make it simpler, more domain specific (#648) * update dsl sample, make it simpler, more domain specific Signed-off-by: Tihomir Surdilovic * update readme Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 2 +- core/build.gradle | 4 - .../temporal/samples/dsl/DslActivities.java | 12 +- .../samples/dsl/DslActivitiesImpl.java | 49 +- .../ActResult.java => DslWorkflow.java} | 34 +- .../samples/dsl/DslWorkflowCache.java | 76 --- .../temporal/samples/dsl/DslWorkflowImpl.java | 68 +++ .../samples/dsl/DynamicDslWorkflow.java | 431 ------------------ .../java/io/temporal/samples/dsl/README.md | 126 +---- .../java/io/temporal/samples/dsl/Starter.java | 150 ++---- .../java/io/temporal/samples/dsl/Worker.java | 39 -- .../dsl/model/{Customer.java => Flow.java} | 40 +- .../samples/dsl/model/FlowAction.java | 79 ++++ .../samples/dsl/model/WorkflowData.java | 73 --- .../samples/dsl/utils/DslWorkflowUtils.java | 161 ------- .../temporal/samples/dsl/utils/JQFilter.java | 91 ---- .../dsl/bankingtransactions/datainput.json | 8 - .../dsl/bankingtransactions/workflow.json | 46 -- .../dsl/bankingtransactions/workflow.yml | 29 -- .../childworkflow.json | 43 -- .../bankingtransactionssubflow/datainput.json | 8 - .../parentworkflow.json | 30 -- .../dsl/customerapplication/datainput.json | 7 - .../dsl/customerapplication/workflow.json | 119 ----- .../dsl/customerapplication/workflow.yml | 68 --- .../customerapproval/applicantdatainput.json | 7 - .../customerapproval/applicantworkflow.json | 55 --- .../customerapproval/approvaldatainput.json | 3 - .../customerapproval/approvalworkflow.json | 102 ----- core/src/main/resources/dsl/sampleflow.json | 27 ++ .../temporal/samples/dsl/DslWorkflowTest.java | 96 +--- .../dsl/bankingtransactions/datainput.json | 8 - .../dsl/bankingtransactions/workflow.json | 46 -- .../dsl/bankingtransactions/workflow.yml | 29 -- .../dsl/customerapplication/datainput.json | 7 - .../dsl/customerapplication/workflow.json | 119 ----- .../dsl/customerapplication/workflow.yml | 68 --- core/src/test/resources/dsl/sampleflow.json | 27 ++ 38 files changed, 316 insertions(+), 2071 deletions(-) rename core/src/main/java/io/temporal/samples/dsl/{model/ActResult.java => DslWorkflow.java} (60%) delete mode 100644 core/src/main/java/io/temporal/samples/dsl/DslWorkflowCache.java create mode 100644 core/src/main/java/io/temporal/samples/dsl/DslWorkflowImpl.java delete mode 100644 core/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java delete mode 100644 core/src/main/java/io/temporal/samples/dsl/Worker.java rename core/src/main/java/io/temporal/samples/dsl/model/{Customer.java => Flow.java} (57%) create mode 100644 core/src/main/java/io/temporal/samples/dsl/model/FlowAction.java delete mode 100644 core/src/main/java/io/temporal/samples/dsl/model/WorkflowData.java delete mode 100644 core/src/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java delete mode 100644 core/src/main/java/io/temporal/samples/dsl/utils/JQFilter.java delete mode 100644 core/src/main/resources/dsl/bankingtransactions/datainput.json delete mode 100644 core/src/main/resources/dsl/bankingtransactions/workflow.json delete mode 100644 core/src/main/resources/dsl/bankingtransactions/workflow.yml delete mode 100644 core/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json delete mode 100644 core/src/main/resources/dsl/bankingtransactionssubflow/datainput.json delete mode 100644 core/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json delete mode 100644 core/src/main/resources/dsl/customerapplication/datainput.json delete mode 100644 core/src/main/resources/dsl/customerapplication/workflow.json delete mode 100644 core/src/main/resources/dsl/customerapplication/workflow.yml delete mode 100644 core/src/main/resources/dsl/customerapproval/applicantdatainput.json delete mode 100644 core/src/main/resources/dsl/customerapproval/applicantworkflow.json delete mode 100644 core/src/main/resources/dsl/customerapproval/approvaldatainput.json delete mode 100644 core/src/main/resources/dsl/customerapproval/approvalworkflow.json create mode 100644 core/src/main/resources/dsl/sampleflow.json delete mode 100644 core/src/test/resources/dsl/bankingtransactions/datainput.json delete mode 100644 core/src/test/resources/dsl/bankingtransactions/workflow.json delete mode 100644 core/src/test/resources/dsl/bankingtransactions/workflow.yml delete mode 100644 core/src/test/resources/dsl/customerapplication/datainput.json delete mode 100644 core/src/test/resources/dsl/customerapplication/workflow.json delete mode 100644 core/src/test/resources/dsl/customerapplication/workflow.yml create mode 100644 core/src/test/resources/dsl/sampleflow.json diff --git a/README.md b/README.md index 323d71c01..3b271dec0 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Money Batch**](/core/src/main/java/io/temporal/samples/moneybatch): Demonstrates a situation where a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. This sample can be easily extended to perform a payment based on more complex criteria, such as at a specific time or an accumulated amount. The sample also demonstrates how to Signal the Workflow when it executes (*Signal with start*). If the Workflow is already executing, it just receives the Signal. If it is not executing, then the Workflow executes first, and then the Signal is delivered to it. *Signal with start* is a "lazy" way to execute Workflows when Signaling them. -- [**Customer Application Approval DSL**](/core/src/main/java/io/temporal/samples/dsl): Demonstrates execution of a customer application approval workflow defined in a DSL (like JSON or YAML) +- [**Domain-Specific-Language - Define sequence of steps in JSON**](/core/src/main/java/io/temporal/samples/dsl): Demonstrates using domain specific language (DSL) defined in JSON to specify sequence of steps to be performed in our workflow. - [**Polling Services**](/core/src/main/java/io/temporal/samples/polling): Recommended implementation of an activity that needs to periodically poll an external resource waiting its successful completion diff --git a/core/build.gradle b/core/build.gradle index 75bb1346f..c73ce2270 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -27,10 +27,6 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-core', version: '4.0.1' implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '4.0.1' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '3.0.0' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-api', version: '4.0.5.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-validation', version: '4.0.5.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-spi', version: '4.0.5.Final' - implementation group: 'io.serverlessworkflow', name: 'serverlessworkflow-util', version: '4.0.5.Final' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20240207' // we don't update it to 2.1.0 because 2.1.0 requires Java 11 diff --git a/core/src/main/java/io/temporal/samples/dsl/DslActivities.java b/core/src/main/java/io/temporal/samples/dsl/DslActivities.java index 5607d10b5..dce8e8bae 100644 --- a/core/src/main/java/io/temporal/samples/dsl/DslActivities.java +++ b/core/src/main/java/io/temporal/samples/dsl/DslActivities.java @@ -20,18 +20,14 @@ package io.temporal.samples.dsl; import io.temporal.activity.ActivityInterface; -import io.temporal.samples.dsl.model.ActResult; -import io.temporal.samples.dsl.model.Customer; @ActivityInterface public interface DslActivities { - ActResult checkCustomerInfo(Customer customer); + String one(); - ActResult approveApplication(Customer customer); + String two(); - ActResult rejectApplication(Customer customer); + String three(); - ActResult updateApplicationInfo(Customer customer); - - ActResult invokeBankingService(Customer customer); + String four(); } diff --git a/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java b/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java index 3fa86c4ad..77aa5df06 100644 --- a/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java @@ -19,53 +19,38 @@ package io.temporal.samples.dsl; -import io.temporal.activity.Activity; -import io.temporal.samples.dsl.model.ActResult; -import io.temporal.samples.dsl.model.Customer; +import java.util.concurrent.TimeUnit; public class DslActivitiesImpl implements DslActivities { @Override - public ActResult checkCustomerInfo(Customer customer) { - try { - return new ActResult(Activity.getExecutionContext().getInfo().getActivityType(), "invoked"); - } catch (Exception e) { - return null; - } + public String one() { + sleep(1); + return "Activity one done..."; } @Override - public ActResult updateApplicationInfo(Customer customer) { - try { - return new ActResult(Activity.getExecutionContext().getInfo().getActivityType(), "invoked"); - } catch (Exception e) { - return null; - } + public String two() { + sleep(1); + return "Activity two done..."; } @Override - public ActResult approveApplication(Customer customer) { - try { - return new ActResult("decision", "APPROVED"); - } catch (Exception e) { - return null; - } + public String three() { + sleep(1); + return "Activity three done..."; } @Override - public ActResult rejectApplication(Customer customer) { - try { - return new ActResult("decision-" + customer.getName(), "DENIED"); - } catch (Exception e) { - return null; - } + public String four() { + sleep(1); + return "Activity four done..."; } - @Override - public ActResult invokeBankingService(Customer customer) { + private void sleep(int seconds) { try { - return new ActResult(Activity.getExecutionContext().getInfo().getActivityType(), "invoked"); - } catch (Exception e) { - return null; + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); + } catch (InterruptedException ee) { + // Empty } } } diff --git a/core/src/main/java/io/temporal/samples/dsl/model/ActResult.java b/core/src/main/java/io/temporal/samples/dsl/DslWorkflow.java similarity index 60% rename from core/src/main/java/io/temporal/samples/dsl/model/ActResult.java rename to core/src/main/java/io/temporal/samples/dsl/DslWorkflow.java index 73c6f708a..9863a43db 100644 --- a/core/src/main/java/io/temporal/samples/dsl/model/ActResult.java +++ b/core/src/main/java/io/temporal/samples/dsl/DslWorkflow.java @@ -17,32 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.samples.dsl.model; +package io.temporal.samples.dsl; -public class ActResult { - private String type; - private String result; +import io.temporal.samples.dsl.model.Flow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; - public ActResult() {} - - public ActResult(String type, String result) { - this.type = type; - this.result = result; - } - - public String getResult() { - return result; - } - - public void setResult(String result) { - this.result = result; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } +@WorkflowInterface +public interface DslWorkflow { + @WorkflowMethod + String run(Flow flow, String input); } diff --git a/core/src/main/java/io/temporal/samples/dsl/DslWorkflowCache.java b/core/src/main/java/io/temporal/samples/dsl/DslWorkflowCache.java deleted file mode 100644 index 555d4beee..000000000 --- a/core/src/main/java/io/temporal/samples/dsl/DslWorkflowCache.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package io.temporal.samples.dsl; - -import static io.temporal.samples.dsl.utils.DslWorkflowUtils.getFileAsString; - -import io.serverlessworkflow.api.Workflow; -import java.util.HashMap; -import java.util.Map; - -/** Class that loads up all the DSL workflows and allows access via id-version */ -public class DslWorkflowCache { - - private static class WorkflowHolder { - static final Map dslWorkflowMap = new HashMap<>(); - - static { - try { - Workflow customerApplicationWorkflow = - Workflow.fromSource(getFileAsString("dsl/customerapplication/workflow.yml")); - Workflow bankingTransactionsWorkflow = - Workflow.fromSource(getFileAsString("dsl/bankingtransactions/workflow.yml")); - Workflow applicantWorkflow = - Workflow.fromSource(getFileAsString("dsl/customerapproval/applicantworkflow.json")); - Workflow approvalWorkflow = - Workflow.fromSource(getFileAsString("dsl/customerapproval/approvalworkflow.json")); - Workflow bankingParentWorkflow = - Workflow.fromSource( - getFileAsString("dsl/bankingtransactionssubflow/parentworkflow.json")); - Workflow bankingChildWorkflow = - Workflow.fromSource( - getFileAsString("dsl/bankingtransactionssubflow/childworkflow.json")); - - dslWorkflowMap.put( - customerApplicationWorkflow.getId() + "-" + customerApplicationWorkflow.getVersion(), - customerApplicationWorkflow); - dslWorkflowMap.put( - bankingTransactionsWorkflow.getId() + "-" + bankingTransactionsWorkflow.getVersion(), - bankingTransactionsWorkflow); - dslWorkflowMap.put( - applicantWorkflow.getId() + "-" + applicantWorkflow.getVersion(), applicantWorkflow); - dslWorkflowMap.put( - approvalWorkflow.getId() + "-" + approvalWorkflow.getVersion(), approvalWorkflow); - dslWorkflowMap.put( - bankingParentWorkflow.getId() + "-" + bankingParentWorkflow.getVersion(), - bankingParentWorkflow); - dslWorkflowMap.put( - bankingChildWorkflow.getId() + "-" + bankingChildWorkflow.getVersion(), - bankingChildWorkflow); - } catch (Exception e) { - System.out.println("Exception: " + e.getMessage()); - } - } - } - - public static Workflow getWorkflow(String workflowId, String workflowVersion) { - return WorkflowHolder.dslWorkflowMap.get(workflowId + "-" + workflowVersion); - } -} diff --git a/core/src/main/java/io/temporal/samples/dsl/DslWorkflowImpl.java b/core/src/main/java/io/temporal/samples/dsl/DslWorkflowImpl.java new file mode 100644 index 000000000..e89d9c52e --- /dev/null +++ b/core/src/main/java/io/temporal/samples/dsl/DslWorkflowImpl.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.dsl; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.RetryOptions; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.ApplicationFailure; +import io.temporal.samples.dsl.model.Flow; +import io.temporal.samples.dsl.model.FlowAction; +import io.temporal.workflow.ActivityStub; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +public class DslWorkflowImpl implements DslWorkflow { + @Override + public String run(Flow flow, String input) { + if (flow == null || flow.getActions().isEmpty()) { + throw ApplicationFailure.newFailure( + "Flow is null or does not have any actions", "illegal flow"); + } + + try { + return runActions(flow, input); + } catch (ActivityFailure e) { + throw ApplicationFailure.newFailure( + "failing execution after compensation initiated", e.getCause().getClass().getName()); + } + } + + private String runActions(Flow flow, String input) { + List results = new ArrayList<>(); + for (FlowAction action : flow.getActions()) { + // build activity options based on flow action input + ActivityOptions.Builder activityOptionsBuilder = ActivityOptions.newBuilder(); + activityOptionsBuilder.setStartToCloseTimeout( + Duration.ofSeconds(action.getStartToCloseSec())); + if (action.getRetries() > 0) { + activityOptionsBuilder.setRetryOptions( + RetryOptions.newBuilder().setMaximumAttempts(action.getRetries()).build()); + } + // create untyped activity stub and run activity based on flow action + ActivityStub activityStub = Workflow.newUntypedActivityStub(activityOptionsBuilder.build()); + + results.add(activityStub.execute(action.getAction(), String.class, input)); + } + return String.join(",", results); + } +} diff --git a/core/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java b/core/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java deleted file mode 100644 index 1464f5fbe..000000000 --- a/core/src/main/java/io/temporal/samples/dsl/DynamicDslWorkflow.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package io.temporal.samples.dsl; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.serverlessworkflow.api.actions.Action; -import io.serverlessworkflow.api.branches.Branch; -import io.serverlessworkflow.api.events.OnEvents; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.functions.SubFlowRef; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.states.*; -import io.serverlessworkflow.api.switchconditions.DataCondition; -import io.serverlessworkflow.utils.WorkflowUtils; -import io.temporal.activity.ActivityOptions; -import io.temporal.api.common.v1.WorkflowExecution; -import io.temporal.api.enums.v1.ParentClosePolicy; -import io.temporal.common.converter.EncodedValues; -import io.temporal.samples.dsl.model.ActResult; -import io.temporal.samples.dsl.model.WorkflowData; -import io.temporal.samples.dsl.utils.DslWorkflowUtils; -import io.temporal.samples.dsl.utils.JQFilter; -import io.temporal.workflow.*; -import java.time.Duration; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.slf4j.Logger; - -public class DynamicDslWorkflow implements DynamicWorkflow { - private static final Logger logger = Workflow.getLogger(DynamicDslWorkflow.class); - - private io.serverlessworkflow.api.Workflow dslWorkflow; - private WorkflowData workflowData = new WorkflowData(); - private List queryFunctions; - private Map signalMap = new HashMap<>(); - - private ActivityStub activities; - - @Override - public Object execute(EncodedValues args) { - // Get first input and convert to SW Workflow object - String dslWorkflowId = args.get(0, String.class); - String dslWorkflowVersion = args.get(1, String.class); - // Get second input which is set to workflowData - workflowData.setValue((ObjectNode) args.get(2, JsonNode.class)); - - // Using a global shared workflow object here is only allowed because its - // assumed that at this point it is immutable and the same across all workflow worker restarts - dslWorkflow = DslWorkflowCache.getWorkflow(dslWorkflowId, dslWorkflowVersion); - - // Get all expression type functions to be used for queries - queryFunctions = - DslWorkflowUtils.getFunctionDefinitionsWithType( - dslWorkflow, FunctionDefinition.Type.EXPRESSION); - - // Register dynamic signal handler - // For demo signals input sets the workflowData - // Improvement can be to add to it instead - Workflow.registerListener( - (DynamicSignalHandler) - (signalName, encodedArgs) -> { - if (workflowData == null) { - workflowData = new WorkflowData(); - } - workflowData.setValue((ObjectNode) encodedArgs.get(0, JsonNode.class)); - signalMap.put(signalName, workflowData); - }); - - // Register dynamic query handler - // we use expression type functions in workflow def as query definitions - Workflow.registerListener( - (DynamicQueryHandler) - (queryType, encodedArgs) -> { - if (queryFunctions == null - || DslWorkflowUtils.getFunctionDefinitionWithName(dslWorkflow, queryType) - == null) { - logger.warn("Unable to find expression function with name: " + queryType); - String queryInput = encodedArgs.get(0, String.class); - if (queryInput == null || queryInput.length() < 1) { - // no input just return workflow data - return workflowData.getValue(); - } else { - return JQFilter.getInstance() - .evaluateExpression(queryInput, workflowData.getValue()); - } - } - return JQFilter.getInstance() - .evaluateExpression( - DslWorkflowUtils.getFunctionDefinitionWithName(dslWorkflow, queryType) - .getOperation(), - workflowData.getValue()); - }); - - // Get the activity options that are set from properties in dsl - ActivityOptions activityOptions = DslWorkflowUtils.getActivityOptionsFromDsl(dslWorkflow); - // Create a dynamic activities stub to be used for all actions in dsl - activities = Workflow.newUntypedActivityStub(activityOptions); - - // Start going through the dsl workflow states and execute depending on their instructions - executeDslWorkflowFrom(WorkflowUtils.getStartingState(dslWorkflow)); - - // Return the final workflow data as result - return workflowData.getValue(); - } - - /** Executes workflow according to the dsl control flow logic */ - private void executeDslWorkflowFrom(State dslWorkflowState) { - // This demo supports 3 states: Event State, Operation State and Switch state (data-based - // switch) - if (dslWorkflowState != null) { - // execute the state and return the next workflow state depending on control flow logic in dsl - // if next state is null it means that we need to stop execution - executeDslWorkflowFrom(executeStateAndReturnNext(dslWorkflowState)); - } else { - // done - return; - } - } - - /** - * Executes the control flow logic for a dsl workflow state. Demo supports EventState, - * OperationState, and SwitchState currently. More can be added. - */ - private State executeStateAndReturnNext(State dslWorkflowState) { - if (dslWorkflowState instanceof EventState) { - EventState eventState = (EventState) dslWorkflowState; - // currently this demo supports only the first onEvents - if (eventState.getOnEvents() != null && eventState.getOnEvents().size() > 0) { - - if (eventState.getOnEvents().get(0).getActions() == null - || eventState.getOnEvents().get(0).getActions().size() < 1) { - // no actions..assume we are just waiting on event here - Workflow.await( - () -> signalMap.containsKey(eventState.getOnEvents().get(0).getEventRefs().get(0))); - workflowData = signalMap.get(eventState.getOnEvents().get(0).getEventRefs().get(0)); - } else { - List eventStateActions = eventState.getOnEvents().get(0).getActions(); - if (eventState.getOnEvents().get(0).getActionMode() != null - && eventState - .getOnEvents() - .get(0) - .getActionMode() - .equals(OnEvents.ActionMode.PARALLEL)) { - List> eventPromises = new ArrayList<>(); - - for (Action action : eventStateActions) { - eventPromises.add( - activities.executeAsync( - action.getFunctionRef().getRefName(), - ActResult.class, - workflowData.getCustomer())); - } - // Invoke all activities in parallel. Wait for all to complete - Promise.allOf(eventPromises).get(); - - for (Promise promise : eventPromises) { - workflowData.addResults(promise.get()); - } - } else { - for (Action action : eventStateActions) { - if (action.getSleep() != null && action.getSleep().getBefore() != null) { - Workflow.sleep(Duration.parse(action.getSleep().getBefore())); - } - // execute the action as an activity and assign its results to workflowData - workflowData.addResults( - activities.execute( - action.getFunctionRef().getRefName(), - ActResult.class, - workflowData.getCustomer())); - if (action.getSleep() != null && action.getSleep().getAfter() != null) { - Workflow.sleep(Duration.parse(action.getSleep().getAfter())); - } - } - } - } - } - if (eventState.getTransition() == null || eventState.getTransition().getNextState() == null) { - return null; - } - return WorkflowUtils.getStateWithName(dslWorkflow, eventState.getTransition().getNextState()); - - } else if (dslWorkflowState instanceof OperationState) { - OperationState operationState = (OperationState) dslWorkflowState; - - if (operationState.getActions() != null && operationState.getActions().size() > 0) { - // Check if actions should be executed sequentially or parallel - if (operationState.getActionMode() != null - && operationState.getActionMode().equals(OperationState.ActionMode.PARALLEL)) { - List> actionsPromises = new ArrayList<>(); - - for (Action action : operationState.getActions()) { - actionsPromises.add( - activities.executeAsync( - action.getFunctionRef().getRefName(), - ActResult.class, - workflowData.getCustomer())); - } - // Invoke all activities in parallel. Wait for all to complete - Promise.allOf(actionsPromises).get(); - - for (Promise promise : actionsPromises) { - workflowData.addResults(promise.get()); - } - } else { - for (Action action : operationState.getActions()) { - // added support for subflow (child workflow) - if (action.getSubFlowRef() != null) { - - if (action.getSubFlowRef().getInvoke() != null - && action.getSubFlowRef().getInvoke().equals(SubFlowRef.Invoke.ASYNC)) { - ChildWorkflowOptions childWorkflowOptions; - - if (action - .getSubFlowRef() - .getOnParentComplete() - .equals(SubFlowRef.OnParentComplete.CONTINUE)) { - childWorkflowOptions = - ChildWorkflowOptions.newBuilder() - .setWorkflowId(action.getSubFlowRef().getWorkflowId()) - .setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON) - .build(); - } else { - childWorkflowOptions = - ChildWorkflowOptions.newBuilder() - .setWorkflowId(action.getSubFlowRef().getWorkflowId()) - .build(); - } - ChildWorkflowStub childWorkflow = - Workflow.newUntypedChildWorkflowStub( - action.getSubFlowRef().getWorkflowId(), childWorkflowOptions); - childWorkflow.executeAsync( - Object.class, - action.getSubFlowRef().getWorkflowId(), - action.getSubFlowRef().getVersion(), - workflowData.getValue()); - // for async we do not care about result in sample - // wait until child starts - Promise childExecution = - Workflow.getWorkflowExecution(childWorkflow); - childExecution.get(); - - } else { - ChildWorkflowStub childWorkflow = - Workflow.newUntypedChildWorkflowStub( - action.getSubFlowRef().getWorkflowId(), - ChildWorkflowOptions.newBuilder() - .setWorkflowId(action.getSubFlowRef().getWorkflowId()) - .build()); - - workflowData.addResults( - childWorkflow.execute( - Object.class, - action.getSubFlowRef().getWorkflowId(), - action.getSubFlowRef().getVersion(), - workflowData.getValue())); - } - } else { - // check if its a custom function - FunctionDefinition functionDefinition = - WorkflowUtils.getFunctionDefinitionsForAction(dslWorkflow, action.getName()); - if (functionDefinition.getType().equals(FunctionDefinition.Type.CUSTOM)) { - // for this example custom function is assumed sending signal via external stub - String[] operationParts = functionDefinition.getOperation().split("#", -1); - ExternalWorkflowStub externalWorkflowStub = - Workflow.newUntypedExternalWorkflowStub(operationParts[0]); - externalWorkflowStub.signal(operationParts[1], workflowData.getValue()); - } else { - if (action.getSleep() != null && action.getSleep().getBefore() != null) { - Workflow.sleep(Duration.parse(action.getSleep().getBefore())); - } - // execute the action as an activity and assign its results to workflowData - workflowData.addResults( - activities.execute( - action.getFunctionRef().getRefName(), - ActResult.class, - workflowData.getCustomer())); - - if (action.getSleep() != null && action.getSleep().getAfter() != null) { - Workflow.sleep(Duration.parse(action.getSleep().getAfter())); - } - } - } - } - } - } - if (operationState.getTransition() == null - || operationState.getTransition().getNextState() == null) { - return null; - } - return WorkflowUtils.getStateWithName( - dslWorkflow, operationState.getTransition().getNextState()); - } else if (dslWorkflowState instanceof SwitchState) { - // Demo supports only data based switch - SwitchState switchState = (SwitchState) dslWorkflowState; - if (switchState.getDataConditions() != null && switchState.getDataConditions().size() > 0) { - // evaluate each condition to see if its true. If none are true default to defaultCondition - for (DataCondition dataCondition : switchState.getDataConditions()) { - if (JQFilter.getInstance() - .evaluateBooleanExpression(dataCondition.getCondition(), workflowData.getValue())) { - if (dataCondition.getTransition() == null - || dataCondition.getTransition().getNextState() == null) { - return null; - } - return WorkflowUtils.getStateWithName( - dslWorkflow, dataCondition.getTransition().getNextState()); - } - } - // no conditions evaluated to true, use default condition - if (switchState.getDefaultCondition().getTransition() == null) { - return null; - } - return WorkflowUtils.getStateWithName( - dslWorkflow, switchState.getDefaultCondition().getTransition().getNextState()); - } else { - // no conditions use the transition/end of default condition - if (switchState.getDefaultCondition().getTransition() == null) { - return null; - } - return WorkflowUtils.getStateWithName( - dslWorkflow, switchState.getDefaultCondition().getTransition().getNextState()); - } - } else if (dslWorkflowState instanceof SleepState) { - SleepState sleepState = (SleepState) dslWorkflowState; - if (sleepState.getDuration() != null) { - Workflow.sleep(Duration.parse(sleepState.getDuration())); - } - if (sleepState.getTransition() == null || sleepState.getTransition().getNextState() == null) { - return null; - } - return WorkflowUtils.getStateWithName(dslWorkflow, sleepState.getTransition().getNextState()); - } else if (dslWorkflowState instanceof ForEachState) { - ForEachState state = (ForEachState) dslWorkflowState; - // List> actionsPromises = new ArrayList<>(); - - List inputs = - JQFilter.getInstance() - .evaluateArrayExpression(state.getInputCollection(), workflowData.getValue()); - // TODO: update to exec all in parallel! - for (JsonNode ignored : inputs) { - for (Action action : state.getActions()) { - if (action.getSleep() != null && action.getSleep().getBefore() != null) { - Workflow.sleep(Duration.parse(action.getSleep().getBefore())); - } - - // execute the action as an activity and assign its results to workflowData - workflowData.addResults( - activities.execute( - action.getFunctionRef().getRefName(), - ActResult.class, - workflowData.getCustomer())); - - if (action.getSleep() != null && action.getSleep().getAfter() != null) { - Workflow.sleep(Duration.parse(action.getSleep().getAfter())); - } - } - } - - if (state.getTransition() == null || state.getTransition().getNextState() == null) { - return null; - } - - return WorkflowUtils.getStateWithName(dslWorkflow, state.getTransition().getNextState()); - } else if (dslWorkflowState instanceof ParallelState) { - ParallelState parallelState = (ParallelState) dslWorkflowState; - - // this is just initial impl, still need to add things like timeouts etc - // also this currently assumes the "allof" completion type (default) - if (parallelState.getBranches() != null && parallelState.getBranches().size() > 0) { - List> branchAllOfPromises = new ArrayList<>(); - - for (Branch branch : parallelState.getBranches()) { - branchAllOfPromises.add(Async.procedure(this::processBranchActions, branch)); - } - - // execute all branch actions in parallel..wait for all to complete - Promise.allOf(branchAllOfPromises).get(); - } - - if (parallelState.getTransition() == null - || parallelState.getTransition().getNextState() == null) { - return null; - } - - return WorkflowUtils.getStateWithName( - dslWorkflow, parallelState.getTransition().getNextState()); - } else { - logger.error("Invalid or unsupported in demo dsl workflow state: " + dslWorkflowState); - return null; - } - } - - private void processBranchActions(Branch branch) { - // here we assume for now that all actions themselves inside - // branch are also executed in parallel, just for sample sake - // we should check the action mode to see if its sequential or parallel - // will add... - List> branchActionPromises = new ArrayList<>(); - List branchActions = branch.getActions(); - for (Action action : branchActions) { - branchActionPromises.add( - activities.executeAsync( - action.getFunctionRef().getRefName(), ActResult.class, workflowData.getCustomer())); - } - - Promise.allOf(branchActionPromises).get(); - - for (Promise promise : branchActionPromises) { - workflowData.addResults(promise.get()); - } - } -} diff --git a/core/src/main/java/io/temporal/samples/dsl/README.md b/core/src/main/java/io/temporal/samples/dsl/README.md index 4ebcf8e02..046cbfe6b 100644 --- a/core/src/main/java/io/temporal/samples/dsl/README.md +++ b/core/src/main/java/io/temporal/samples/dsl/README.md @@ -1,134 +1,20 @@ # DSL Sample This sample shows how to use a DSL on top of Temporal. +The sample defines a number of domain specific json samples +which are used to define steps of actions to be performed by our workflow. -The sample uses CNCF Serverless Workflow (serverlessworkflow.io) DSL and its Java SDK, -which helps us parse the DSL into an object model as well as provides DSL validation. - -Note: Temporal helps you to focus on business logic. We handle the complexities of building scalable distributed systems so you can deliver reliable workflows faster. -Our approach helps you build the tooling you need, without restricting functionality. As with all samples, use the following at your own risk. -Temporal does not endorse the use of CNCF Serverless Workflows; the following code is just an example. + As a rule, DSLs provide limited and restrictive functionality. They are not suitable for full expressive development. -In many cases, it's better to build customized DSLs to optimize simplicity and domain targeting for your particular use case. - -This sample runs the following DSL workflows: -1. [`customerapplication/workflow.yml`](../../../../../resources/dsl/customerapplication/workflow.yml) -2. [`bankingtransactions/workflow.yml`](../../../../../resources/dsl/bankingtransactions/workflow.yml) -3. [`customerapproval/applicantworkflow.json`](../../../../../resources/dsl/customerapproval/applicantworkflow.json) -4. [`customerapproval/approvalworkflow.json`](../../../../../resources/dsl/customerapproval/approvalworkflow.json) -5. [`bankingtransactionssubflow/parentworkflow.json`](../../../../../resources/dsl/bankingtransactionssubflow/parentworkflow.json) -6. [`bankingtransactionssubflow/childworkflow.json`](../../../../../resources/dsl/bankingtransactionssubflow/childworkflow.json) -Note that most DSLs, including Serverless Workflow DSL used in this sample represent -their Workflow data as JSON. As such manipulation of this data is done via expression languages -that specilize in manipulating JSON. In this case we use `jq`. You can plug in your expression language -of choice. +In many cases, it's better to build customized DSLs to optimize simplicity and domain targeting for your particular use case. ## Run the sample -1. Start the Worker: - -```bash -./gradlew -q execute -PmainClass=io.temporal.samples.dsl.Worker -``` - -2. Start the Starter +1Start the Starter ```bash ./gradlew -q execute -PmainClass=io.temporal.samples.dsl.Starter -``` - -You should see results: - -```text -Validating workflow: customerapplication -Starting workflow with id: customerapplication and version: 1.0 -Query result for customer name: John -Query result for customer age: 22 -Workflow results: -{ - "customer" : { - "name" : "John", - "age" : 22 - }, - "results" : [ { - "type" : "CheckCustomerInfo", - "result" : "invoked" - }, { - "type" : "UpdateApplicationInfo", - "result" : "invoked" - }, { - "type" : "decision", - "result" : "APPROVED" - } ] -} -Validating workflow: bankingtransactions -Starting workflow with id: bankingtransactions and version: 1.0 -Query result for customer name: John -Query result for customer age: 22 -Workflow results: -{ - "customer" : { - "name" : "John", - "age" : 22, - "transactions" : [ 100, -50, 20 ] - }, - "results" : [ { - "type" : "InvokeBankingService", - "result" : "invoked" - }, { - "type" : "InvokeBankingService", - "result" : "invoked" - }, { - "type" : "InvokeBankingService", - "result" : "invoked" - } ] -} -Validating workflow: applicantworkflow -Validating workflow: approvalworkflow -Starting workflow with id: approvalworkflow and version: 1.0 -Starting workflow with id: applicantworkflow and version: 1.0 -Workflow results: -{ - "customer" : { - "name" : "John", - "age" : 22 - }, - "results" : [ { - "type" : "decision", - "result" : "APPROVED" - } ] -} -Validating workflow: bankingparentworkflow -Starting workflow with id: bankingparentworkflow and version: 1.0 -Workflow results: -{ - "customer" : { - "name" : "John", - "age" : 22, - "transactions" : [ 100, -50, 20 ] - }, - "results" : [ { - "customer" : { - "name" : "John", - "age" : 22, - "transactions" : [ 100, -50, 20 ] - }, - "results" : [ { - "type" : "InvokeBankingService", - "result" : "invoked" - }, { - "type" : "InvokeBankingService", - "result" : "invoked" - }, { - "type" : "InvokeBankingService", - "result" : "invoked" - } ] - } ] -} -``` - - - +``` \ No newline at end of file diff --git a/core/src/main/java/io/temporal/samples/dsl/Starter.java b/core/src/main/java/io/temporal/samples/dsl/Starter.java index 644f492f9..47b2a5035 100644 --- a/core/src/main/java/io/temporal/samples/dsl/Starter.java +++ b/core/src/main/java/io/temporal/samples/dsl/Starter.java @@ -19,19 +19,13 @@ package io.temporal.samples.dsl; -import static io.temporal.samples.dsl.utils.DslWorkflowUtils.*; - -import com.fasterxml.jackson.databind.JsonNode; -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.WorkflowValidator; -import io.serverlessworkflow.api.validation.ValidationError; -import io.serverlessworkflow.validation.WorkflowValidatorImpl; +import com.fasterxml.jackson.databind.ObjectMapper; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; -import io.temporal.client.WorkflowStub; +import io.temporal.samples.dsl.model.Flow; import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; -import java.util.List; public class Starter { @@ -40,131 +34,39 @@ public class Starter { public static final WorkerFactory factory = WorkerFactory.newInstance(client); public static void main(String[] args) { + Flow flow = getFlowFromResource(); - // Customer application workflow - runCustomerApplicationWorkflow(); - // Banking transaction workflow - runBankingTransactionWorkflow(); - // Customer approval workflow - runCustomerApprovalWorkflow(); - // Banking transaction workflow with parent/child relationship - runBankingTransactionWithChildWorkflow(); - - System.exit(0); - } - - private static void runCustomerApplicationWorkflow() { - runWorkflow("customerapplication", "1.0", "dsl/customerapplication/datainput.json", true); - } - - private static void runBankingTransactionWorkflow() { - runWorkflow("bankingtransactions", "1.0", "dsl/bankingtransactions/datainput.json", true); - } - - private static void runBankingTransactionWithChildWorkflow() { - runWorkflow( - "bankingparentworkflow", "1.0", "dsl/bankingtransactionssubflow/datainput.json", false); - } - - private static void runWorkflow( - String workflowId, String workflowVersion, String dataInputFileName, boolean doQuery) { - try { - // Get the workflow dsl from cache - Workflow dslWorkflow = DslWorkflowCache.getWorkflow(workflowId, workflowVersion); - - assertValid(dslWorkflow); - - WorkflowOptions workflowOptions = getWorkflowOptions(dslWorkflow); - - WorkflowStub workflowStub = - client.newUntypedWorkflowStub(dslWorkflow.getName(), workflowOptions); + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker("dsl-task-queue"); + worker.registerWorkflowImplementationTypes(DslWorkflowImpl.class); + worker.registerActivitiesImplementations(new DslActivitiesImpl()); + factory.start(); - System.out.println( - "Starting workflow with id: " + workflowId + " and version: " + workflowVersion); - // Start workflow execution - startWorkflow(workflowStub, dslWorkflow, getSampleWorkflowInput(dataInputFileName)); + DslWorkflow workflow = + client.newWorkflowStub( + DslWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId("dsl-workflow") + .setTaskQueue("dsl-task-queue") + .build()); - // Wait for workflow to finish - JsonNode result = workflowStub.getResult(JsonNode.class); + String result = workflow.run(flow, "sample input"); - if (doQuery) { - // Query the customer name and age - String customerName = workflowStub.query("QueryCustomerName", String.class); - int customerAge = workflowStub.query("QueryCustomerAge", Integer.class); + System.out.println("Result: " + result); - System.out.println("Query result for customer name: " + customerName); - System.out.println("Query result for customer age: " + customerAge); - } - - // Print workflow results - System.out.println("Workflow results: \n" + result.toPrettyString()); - - } catch (Exception e) { - e.printStackTrace(); - System.err.println("Error: " + e.getMessage()); - } + System.exit(0); } - private static void runCustomerApprovalWorkflow() { + private static Flow getFlowFromResource() { + ObjectMapper objectMapper = new ObjectMapper(); try { - Workflow applicantWorkflow = DslWorkflowCache.getWorkflow("applicantworkflow", "1.0"); - Workflow approvalWorkflow = DslWorkflowCache.getWorkflow("approvalworkflow", "1.0"); - - assertValid(applicantWorkflow); - assertValid(approvalWorkflow); - - // start approval workflow first - WorkflowStub approvalWorkflowStub = - client.newUntypedWorkflowStub( - approvalWorkflow.getName(), getWorkflowOptions(approvalWorkflow)); - System.out.println( - "Starting workflow with id: " - + approvalWorkflow.getId() - + " and version: " - + applicantWorkflow.getVersion()); - startWorkflow( - approvalWorkflowStub, - approvalWorkflow, - getSampleWorkflowInput("dsl/customerapproval/approvaldatainput.json")); - - // start applicant workflow second - WorkflowStub applicantWorkflowStub = - client.newUntypedWorkflowStub( - applicantWorkflow.getName(), getWorkflowOptions(applicantWorkflow)); - System.out.println( - "Starting workflow with id: " - + applicantWorkflow.getId() - + " and version: " - + applicantWorkflow.getVersion()); - startWorkflow( - applicantWorkflowStub, - applicantWorkflow, - getSampleWorkflowInput("dsl/customerapproval/applicantdatainput.json")); - - // Wait for workflow to finish - JsonNode result = applicantWorkflowStub.getResult(JsonNode.class); - // Print workflow results - System.out.println("Workflow results: \n" + result.toPrettyString()); - + return objectMapper.readValue( + Starter.class.getClassLoader().getResource("dsl/sampleflow.json"), Flow.class); } catch (Exception e) { e.printStackTrace(); - System.err.println("Error: " + e.getMessage()); - } - } - - private static void assertValid(Workflow dslWorkflow) { - // Validate dsl - System.out.println("Validating workflow: " + dslWorkflow.getId()); - WorkflowValidator dslWorkflowValidator = new WorkflowValidatorImpl(); - if (!dslWorkflowValidator.setWorkflow(dslWorkflow).isValid()) { - System.err.println( - "Workflow DSL not valid. Consult github.com/serverlessworkflow/specification/blob/main/specification.md for more info"); - List validationErrorList = - dslWorkflowValidator.setWorkflow(dslWorkflow).validate(); - for (ValidationError error : validationErrorList) { - System.out.println("Error: " + error.getMessage()); - } - System.exit(1); + return null; } } } diff --git a/core/src/main/java/io/temporal/samples/dsl/Worker.java b/core/src/main/java/io/temporal/samples/dsl/Worker.java deleted file mode 100644 index 982a0908c..000000000 --- a/core/src/main/java/io/temporal/samples/dsl/Worker.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package io.temporal.samples.dsl; - -import io.temporal.client.WorkflowClient; -import io.temporal.serviceclient.WorkflowServiceStubs; -import io.temporal.worker.WorkerFactory; - -public class Worker { - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); - private static final WorkerFactory factory = WorkerFactory.newInstance(client); - public static final String DEFAULT_TASK_QUEUE_NAME = "dsltaskqueue"; - - public static void main(String[] args) { - io.temporal.worker.Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); - worker.registerWorkflowImplementationTypes(DynamicDslWorkflow.class); - worker.registerActivitiesImplementations(new DslActivitiesImpl()); - - factory.start(); - } -} diff --git a/core/src/main/java/io/temporal/samples/dsl/model/Customer.java b/core/src/main/java/io/temporal/samples/dsl/model/Flow.java similarity index 57% rename from core/src/main/java/io/temporal/samples/dsl/model/Customer.java rename to core/src/main/java/io/temporal/samples/dsl/model/Flow.java index e90f0961c..22e9d3254 100644 --- a/core/src/main/java/io/temporal/samples/dsl/model/Customer.java +++ b/core/src/main/java/io/temporal/samples/dsl/model/Flow.java @@ -21,10 +21,28 @@ import java.util.List; -public class Customer { +public class Flow { + private String id; private String name; - private int age; - private List transactions; + private String description; + private List actions; + + public Flow() {} + + public Flow(String id, String name, String description, List actions) { + this.id = id; + this.name = name; + this.description = description; + this.actions = actions; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } public String getName() { return name; @@ -34,19 +52,19 @@ public void setName(String name) { this.name = name; } - public int getAge() { - return age; + public String getDescription() { + return description; } - public void setAge(int age) { - this.age = age; + public void setDescription(String description) { + this.description = description; } - public List getTransactions() { - return transactions; + public List getActions() { + return actions; } - public void setTransactions(List transactions) { - this.transactions = transactions; + public void setActions(List actions) { + this.actions = actions; } } diff --git a/core/src/main/java/io/temporal/samples/dsl/model/FlowAction.java b/core/src/main/java/io/temporal/samples/dsl/model/FlowAction.java new file mode 100644 index 000000000..f1f9a367c --- /dev/null +++ b/core/src/main/java/io/temporal/samples/dsl/model/FlowAction.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.dsl.model; + +public class FlowAction { + private String action; + private String compensateBy; + private int retries; + private int startToCloseSec; + private int next; + + public FlowAction() {} + + public FlowAction( + String action, String compensateBy, int retries, int startToCloseSec, int next) { + this.action = action; + this.compensateBy = compensateBy; + this.retries = retries; + this.startToCloseSec = startToCloseSec; + this.next = next; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getCompensateBy() { + return compensateBy; + } + + public void setCompensateBy(String compensateBy) { + this.compensateBy = compensateBy; + } + + public int getRetries() { + return retries; + } + + public void setRetries(int retries) { + this.retries = retries; + } + + public int getStartToCloseSec() { + return startToCloseSec; + } + + public void setStartToCloseSec(int startToCloseSec) { + this.startToCloseSec = startToCloseSec; + } + + public int getNext() { + return next; + } + + public void setNext(int next) { + this.next = next; + } +} diff --git a/core/src/main/java/io/temporal/samples/dsl/model/WorkflowData.java b/core/src/main/java/io/temporal/samples/dsl/model/WorkflowData.java deleted file mode 100644 index 60bb96851..000000000 --- a/core/src/main/java/io/temporal/samples/dsl/model/WorkflowData.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package io.temporal.samples.dsl.model; - -import com.fasterxml.jackson.core.JacksonException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -public class WorkflowData { - - private static final ObjectMapper mapper = new ObjectMapper(); - private ObjectNode value; - - public WorkflowData() { - value = mapper.createObjectNode(); - } - - public WorkflowData(String data) { - try { - if (data == null || data.trim().length() < 1) { - value = mapper.createObjectNode(); - } else { - value = (ObjectNode) mapper.readTree(data); - } - // value.putArray("results"); - } catch (JacksonException e) { - throw new IllegalArgumentException("Invalid workflow data input: " + e.getMessage()); - } - } - - public Customer getCustomer() { - try { - return mapper.readValue(value.get("customer").toPrettyString(), Customer.class); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - public ObjectNode getValue() { - return value; - } - - public void setValue(ObjectNode value) { - this.value = value; - } - - public void addResults(Object result) { - ((ArrayNode) this.value.get("results")).add(mapper.valueToTree(result)); - } - - public String valueToString() { - return value.toPrettyString(); - } -} diff --git a/core/src/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java b/core/src/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java deleted file mode 100644 index 3deade730..000000000 --- a/core/src/main/java/io/temporal/samples/dsl/utils/DslWorkflowUtils.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package io.temporal.samples.dsl.utils; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.retry.RetryDefinition; -import io.serverlessworkflow.api.states.EventState; -import io.serverlessworkflow.utils.WorkflowUtils; -import io.temporal.activity.ActivityOptions; -import io.temporal.api.common.v1.WorkflowExecution; -import io.temporal.client.WorkflowOptions; -import io.temporal.client.WorkflowStub; -import io.temporal.common.RetryOptions; -import io.temporal.samples.dsl.Starter; -import io.temporal.samples.dsl.Worker; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.time.Duration; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -/** Provides utility methods for dealing with DSL */ -public class DslWorkflowUtils { - - /** Set workflow options from DSL */ - public static WorkflowOptions getWorkflowOptions(Workflow workflow) { - WorkflowOptions.Builder dslWorkflowOptionsBuilder = WorkflowOptions.newBuilder(); - - if (workflow.getId() != null) { - dslWorkflowOptionsBuilder.setWorkflowId(workflow.getId()); - } - - dslWorkflowOptionsBuilder.setTaskQueue(Worker.DEFAULT_TASK_QUEUE_NAME); - - if (workflow.getTimeouts() != null - && workflow.getTimeouts().getWorkflowExecTimeout() != null - && workflow.getTimeouts().getWorkflowExecTimeout().getDuration() != null) { - dslWorkflowOptionsBuilder.setWorkflowExecutionTimeout( - Duration.parse(workflow.getTimeouts().getWorkflowExecTimeout().getDuration())); - } - - if (workflow.getStart() != null - && workflow.getStart().getSchedule() != null - && workflow.getStart().getSchedule().getCron() != null) { - dslWorkflowOptionsBuilder.setCronSchedule( - workflow.getStart().getSchedule().getCron().getExpression()); - } - - return dslWorkflowOptionsBuilder.build(); - } - - /** Set Activity options from DSL */ - public static ActivityOptions getActivityOptionsFromDsl(Workflow dslWorkflow) { - ActivityOptions.Builder dslActivityOptionsBuilder = ActivityOptions.newBuilder(); - if (dslWorkflow.getTimeouts() != null - && dslWorkflow.getTimeouts().getActionExecTimeout() != null) { - dslActivityOptionsBuilder.setStartToCloseTimeout( - Duration.parse(dslWorkflow.getTimeouts().getActionExecTimeout())); - } - - // In SW spec each action (activity) can define a specific retry - // For this demo we just use the globally defined one for all actions - if (dslWorkflow.getRetries() != null - && dslWorkflow.getRetries().getRetryDefs() != null - && dslWorkflow.getRetries().getRetryDefs().size() > 0) { - RetryDefinition retryDefinition = dslWorkflow.getRetries().getRetryDefs().get(0); - RetryOptions.Builder dslRetryOptionsBuilder = RetryOptions.newBuilder(); - if (retryDefinition.getMaxAttempts() != null) { - dslRetryOptionsBuilder.setMaximumAttempts( - Integer.parseInt(retryDefinition.getMaxAttempts())); - } - dslRetryOptionsBuilder.setBackoffCoefficient(1.0); - if (retryDefinition.getDelay() != null) { - dslRetryOptionsBuilder.setInitialInterval(Duration.parse(retryDefinition.getDelay())); - } - if (retryDefinition.getMaxDelay() != null) { - dslRetryOptionsBuilder.setMaximumInterval(Duration.parse(retryDefinition.getMaxDelay())); - } - } - - return dslActivityOptionsBuilder.build(); - } - - /** Read file and return contents as string */ - public static String getFileAsString(String fileName) throws IOException { - File file = new File(Starter.class.getClassLoader().getResource(fileName).getFile()); - return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - } - - /** Start workflow execution depending on the DSL */ - public static WorkflowExecution startWorkflow( - WorkflowStub workflowStub, Workflow dslWorkflow, JsonNode workflowInput) { - State startingDslWorkflowState = WorkflowUtils.getStartingState(dslWorkflow); - if (startingDslWorkflowState instanceof EventState) { - // This demo can parse only the first event - EventState eventState = (EventState) startingDslWorkflowState; - String eventName = eventState.getOnEvents().get(0).getEventRefs().get(0); - - if (eventState.getOnEvents().get(0).getActions() == null - || eventState.getOnEvents().get(0).getActions().size() < 1) { - return workflowStub.start(dslWorkflow.getId(), dslWorkflow.getVersion(), workflowInput); - } else { - // send input data as signal data - return workflowStub.signalWithStart( - eventName, - new Object[] {workflowInput}, - new Object[] {dslWorkflow.getId(), dslWorkflow.getVersion()}); - } - } else { - // directly send input data to workflow - return workflowStub.start(dslWorkflow.getId(), dslWorkflow.getVersion(), workflowInput); - } - } - - public static FunctionDefinition getFunctionDefinitionWithName(Workflow workflow, String name) { - if (!WorkflowUtils.hasFunctionDefs(workflow)) return null; - Optional funcDef = - workflow.getFunctions().getFunctionDefs().stream() - .filter(fd -> fd.getName().equals(name)) - .findFirst(); - return funcDef.orElse(null); - } - - public static List getFunctionDefinitionsWithType( - Workflow workflow, FunctionDefinition.Type type) { - if (!WorkflowUtils.hasFunctionDefs(workflow)) return null; - return workflow.getFunctions().getFunctionDefs().stream() - .filter(fd -> fd.getType().equals(type)) - .collect(Collectors.toList()); - } - - public static JsonNode getSampleWorkflowInput(String fileName) throws Exception { - String workflowDataInput = getFileAsString(fileName); - ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readTree(workflowDataInput); - } -} diff --git a/core/src/main/java/io/temporal/samples/dsl/utils/JQFilter.java b/core/src/main/java/io/temporal/samples/dsl/utils/JQFilter.java deleted file mode 100644 index 4967d8d6f..000000000 --- a/core/src/main/java/io/temporal/samples/dsl/utils/JQFilter.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package io.temporal.samples.dsl.utils; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.BooleanNode; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import net.thisptr.jackson.jq.BuiltinFunctionLoader; -import net.thisptr.jackson.jq.JsonQuery; -import net.thisptr.jackson.jq.Scope; -import net.thisptr.jackson.jq.Versions; -import net.thisptr.jackson.jq.module.loaders.BuiltinModuleLoader; - -public class JQFilter { - - private static final Scope rootScope = Scope.newEmptyScope(); - private static Map expressionMap = new HashMap<>(); - - private static volatile JQFilter instance; - - public static JQFilter getInstance() { - if (instance == null) { - synchronized (JQFilter.class) { - if (instance == null) { - instance = new JQFilter(); - } - } - } - return instance; - } - - private JQFilter() { - BuiltinFunctionLoader.getInstance().loadFunctions(Versions.JQ_1_6, rootScope); - rootScope.setModuleLoader(BuiltinModuleLoader.getInstance()); - } - - public JsonNode evaluateExpression(String expression, JsonNode data) { - - try { - - final Scope childScope = Scope.newChildScope(rootScope); - final List result = new ArrayList<>(); - - final String toEvalExpression = expression.replace("${", "").replaceAll("}$", ""); - - if (!expressionMap.containsKey(toEvalExpression)) { - expressionMap.put(toEvalExpression, JsonQuery.compile(toEvalExpression, Versions.JQ_1_6)); - } - - expressionMap.get(toEvalExpression).apply(childScope, data, result::add); - - return result.get(0); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public boolean evaluateBooleanExpression(String expression, JsonNode data) { - BooleanNode result = (BooleanNode) evaluateExpression(expression, data); - return result.booleanValue(); - } - - public List evaluateArrayExpression(String expression, JsonNode data) { - ArrayNode result = (ArrayNode) evaluateExpression(expression, data); - List resultList = new ArrayList<>(result.size()); - result.forEach(jsonNode -> resultList.add(jsonNode)); - - return resultList; - } -} diff --git a/core/src/main/resources/dsl/bankingtransactions/datainput.json b/core/src/main/resources/dsl/bankingtransactions/datainput.json deleted file mode 100644 index 8fee3af06..000000000 --- a/core/src/main/resources/dsl/bankingtransactions/datainput.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "customer": { - "name": "John", - "age": 22, - "transactions": [100, -50, 20] - }, - "results": [] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/bankingtransactions/workflow.json b/core/src/main/resources/dsl/bankingtransactions/workflow.json deleted file mode 100644 index a510178c8..000000000 --- a/core/src/main/resources/dsl/bankingtransactions/workflow.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "id": "bankingtransactions", - "name": "Customer Banking Transactions Workflow", - "version": "1.0", - "specVersion": "0.8", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1M" - }, - "actionExecTimeout": "PT10S" - }, - "autoRetries": true, - "start": "ProcessTransactions", - "states": [ - { - "name": "ProcessTransactions", - "type": "foreach", - "inputCollection": "${ .customer.transactions }", - "iterationParam": "${ .tx }", - "mode": "parallel", - "actions": [ - { - "name": "Processing Action", - "functionRef": "InvokeBankingService" - } - ], - "end": true - } - ], - "functions": [ - { - "name": "InvokeBankingService", - "type": "rest" - }, - { - "name": "QueryCustomerName", - "type": "expression", - "operation": "${ .customer.name }" - }, - { - "name": "QueryCustomerAge", - "type": "expression", - "operation": "${ .customer.age }" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/bankingtransactions/workflow.yml b/core/src/main/resources/dsl/bankingtransactions/workflow.yml deleted file mode 100644 index b1fb45f4d..000000000 --- a/core/src/main/resources/dsl/bankingtransactions/workflow.yml +++ /dev/null @@ -1,29 +0,0 @@ -id: bankingtransactions -name: Customer Banking Transactions Workflow -version: '1.0' -specVersion: '0.8' -timeouts: - workflowExecTimeout: - duration: PT1M - actionExecTimeout: PT10S -autoRetries: true -start: ProcessTransactions -states: - - name: ProcessTransactions - type: foreach - inputCollection: "${ .customer.transactions }" - iterationParam: "${ .tx }" - mode: parallel - actions: - - name: Processing Action - functionRef: InvokeBankingService - end: true -functions: - - name: InvokeBankingService - type: rest - - name: QueryCustomerName - type: expression - operation: "${ .customer.name }" - - name: QueryCustomerAge - type: expression - operation: "${ .customer.age }" diff --git a/core/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json b/core/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json deleted file mode 100644 index b70ccb13c..000000000 --- a/core/src/main/resources/dsl/bankingtransactionssubflow/childworkflow.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "id": "bankingchildworkflow", - "name": "Customer Banking Transactions Child Workflow", - "version": "1.0", - "specVersion": "0.8", - "timeouts": { - "actionExecTimeout": "PT10S" - }, - "autoRetries": true, - "start": "ProcessTransactions", - "states": [ - { - "name": "ProcessTransactions", - "type": "foreach", - "inputCollection": "${ .customer.transactions }", - "iterationParam": "${ .tx }", - "mode": "parallel", - "actions": [ - { - "name": "Processing Action", - "functionRef": "InvokeBankingService" - } - ], - "end": true - } - ], - "functions": [ - { - "name": "InvokeBankingService", - "type": "rest" - }, - { - "name": "QueryCustomerName", - "type": "expression", - "operation": "${ .customer.name }" - }, - { - "name": "QueryCustomerAge", - "type": "expression", - "operation": "${ .customer.age }" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/bankingtransactionssubflow/datainput.json b/core/src/main/resources/dsl/bankingtransactionssubflow/datainput.json deleted file mode 100644 index 8fee3af06..000000000 --- a/core/src/main/resources/dsl/bankingtransactionssubflow/datainput.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "customer": { - "name": "John", - "age": 22, - "transactions": [100, -50, 20] - }, - "results": [] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json b/core/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json deleted file mode 100644 index 3f45e6da4..000000000 --- a/core/src/main/resources/dsl/bankingtransactionssubflow/parentworkflow.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "id": "bankingparentworkflow", - "name": "Customer Banking Transactions Parent Workflow", - "version": "1.0", - "specVersion": "0.8", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1M" - }, - "actionExecTimeout": "PT10S" - }, - "autoRetries": true, - "start": "InvokeBankingChild", - "states": [ - { - "name": "InvokeBankingChild", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "subFlowRef": { - "workflowId": "bankingchildworkflow", - "version": "1.0" - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/customerapplication/datainput.json b/core/src/main/resources/dsl/customerapplication/datainput.json deleted file mode 100644 index 19f754c37..000000000 --- a/core/src/main/resources/dsl/customerapplication/datainput.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "customer": { - "name": "John", - "age": 22 - }, - "results": [] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/customerapplication/workflow.json b/core/src/main/resources/dsl/customerapplication/workflow.json deleted file mode 100644 index 6b099c8f9..000000000 --- a/core/src/main/resources/dsl/customerapplication/workflow.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "id": "customerapplication", - "name": "Customer Application Workflow", - "version": "1.0", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1M" - }, - "actionExecTimeout": "PT10S" - }, - "retries": [ - { - "name": "WorkflowRetries", - "delay": "PT3S", - "maxAttempts": 10 - } - ], - "states": [ - { - "name": "NewCustomerApplication", - "type": "event", - "onEvents": [{ - "eventRefs": ["NewApplicationEvent"], - "actionMode": "parallel", - "actions":[ - { - "name": "Invoke Check Customer Info Function", - "functionRef": "CheckCustomerInfo" - }, - { - "name": "Invoke Update Application Info Function", - "functionRef": "UpdateApplicationInfo" - } - ] - }], - "transition": "MakeApplicationDecision" - }, - { - "name": "MakeApplicationDecision", - "type": "switch", - "dataConditions": [ - { - "condition": "${ .customer.age >= 20 }", - "transition": "ApproveApplication" - }, - { - "condition": "${ .customer.age < 20 }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "ApproveApplication", - "type": "operation", - "actions": [ - { - "name": "Invoke Approve Application Function", - "functionRef": "ApproveApplication", - "sleep": { - "before": "PT1S" - } - } - ], - "end": true - }, - { - "name": "RejectApplication", - "type": "operation", - "actions": [ - { - "name": "Invoke Reject Application Function", - "functionRef": "RejectApplication", - "sleep": { - "before": "PT1S" - } - } - ], - "end": true - } - ], - "functions": [ - { - "name": "CheckCustomerInfo", - "type": "rest" - }, - { - "name": "UpdateApplicationInfo", - "type": "rest" - }, - { - "name": "ApproveApplication", - "type": "rest" - }, - { - "name": "RejectApplication", - "type": "rest" - }, - { - "name": "QueryCustomerName", - "type": "expression", - "operation": "${ .customer.name }" - }, - { - "name": "QueryCustomerAge", - "type": "expression", - "operation": "${ .customer.age }" - } - ], - "events": [ - { - "name": "NewApplicationEvent", - "type": "com.fasterxml.jackson.databind.JsonNode", - "source": "applicationsSource" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/customerapplication/workflow.yml b/core/src/main/resources/dsl/customerapplication/workflow.yml deleted file mode 100644 index 996c5376a..000000000 --- a/core/src/main/resources/dsl/customerapplication/workflow.yml +++ /dev/null @@ -1,68 +0,0 @@ -id: customerapplication -name: Customer Application Workflow -version: '1.0' -timeouts: - workflowExecTimeout: - duration: PT1M - actionExecTimeout: PT10S -retries: - - name: WorkflowRetries - delay: PT3S - maxAttempts: 10 -states: - - name: NewCustomerApplication - type: event - onEvents: - - eventRefs: - - NewApplicationEvent - actionMode: parallel - actions: - - name: Invoke Check Customer Info Function - functionRef: CheckCustomerInfo - - name: Invoke Update Application Info Function - functionRef: UpdateApplicationInfo - transition: MakeApplicationDecision - - name: MakeApplicationDecision - type: switch - dataConditions: - - condition: "${ .customer.age >= 20 }" - transition: ApproveApplication - - condition: "${ .customer.age < 20 }" - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: ApproveApplication - type: operation - actions: - - name: Invoke Approve Application Function - functionRef: ApproveApplication - sleep: - before: PT1S - end: true - - name: RejectApplication - type: operation - actions: - - name: Invoke Reject Application Function - functionRef: RejectApplication - sleep: - before: PT1S - end: true -functions: - - name: CheckCustomerInfo - type: rest - - name: UpdateApplicationInfo - type: rest - - name: ApproveApplication - type: rest - - name: RejectApplication - type: rest - - name: QueryCustomerName - type: expression - operation: "${ .customer.name }" - - name: QueryCustomerAge - type: expression - operation: "${ .customer.age }" -events: - - name: NewApplicationEvent - type: com.fasterxml.jackson.databind.JsonNode - source: applicationsSource diff --git a/core/src/main/resources/dsl/customerapproval/applicantdatainput.json b/core/src/main/resources/dsl/customerapproval/applicantdatainput.json deleted file mode 100644 index 19f754c37..000000000 --- a/core/src/main/resources/dsl/customerapproval/applicantdatainput.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "customer": { - "name": "John", - "age": 22 - }, - "results": [] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/customerapproval/applicantworkflow.json b/core/src/main/resources/dsl/customerapproval/applicantworkflow.json deleted file mode 100644 index 523e52ab9..000000000 --- a/core/src/main/resources/dsl/customerapproval/applicantworkflow.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "id": "applicantworkflow", - "name": "Applicant Processing Workflow", - "version": "1.0", - "specVersion": "0.8", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT2M" - }, - "actionExecTimeout": "PT10S" - }, - "autoRetries": true, - "states": [ - { - "name":"ApproveApplicant", - "type":"operation", - "actions":[ - { - "name": "approvalAction", - "functionRef": { - "refName": "approvalFunction", - "arguments": { - "customer": "${ .customer }" - } - } - } - ], - "transition": "WaitForDecision" - }, - { - "name":"WaitForDecision", - "type": "event", - "onEvents": [ - { - "eventRefs": ["CustomerDecision"] - } - ], - "end": true - } - ], - "functions": [ - { - "name": "approvalFunction", - "type": "custom", - "operation": "approvalworkflow#ToApproveCustomer" - } - ], - "events": [ - { - "name": "CustomerDecision", - "type": "com.fasterxml.jackson.databind.JsonNode", - "source": "applicationsSource" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/customerapproval/approvaldatainput.json b/core/src/main/resources/dsl/customerapproval/approvaldatainput.json deleted file mode 100644 index 914332edb..000000000 --- a/core/src/main/resources/dsl/customerapproval/approvaldatainput.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "results": [] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/customerapproval/approvalworkflow.json b/core/src/main/resources/dsl/customerapproval/approvalworkflow.json deleted file mode 100644 index 5665199ae..000000000 --- a/core/src/main/resources/dsl/customerapproval/approvalworkflow.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "id": "approvalworkflow", - "name": "Customer Approval Workflow", - "version": "1.0", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1M" - }, - "actionExecTimeout": "PT10S" - }, - "states": [ - { - "name":"WaitForCustomer", - "type": "event", - "onEvents": [ - { - "eventRefs": ["ToApproveCustomer"] - } - ], - "transition": "MakeApplicationDecision" - }, - - - { - "name": "MakeApplicationDecision", - "type": "switch", - "dataConditions": [ - { - "condition": "${ .customer.age >= 20 }", - "transition": "ApproveApplication" - }, - { - "condition": "${ .customer.age < 20 }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "ApproveApplication", - "type": "operation", - "actions": [ - { - "name": "Invoke Approve Application Function", - "functionRef": "ApproveApplication" - } - ], - "transition": "SendBackResults" - }, - { - "name": "RejectApplication", - "type": "operation", - "actions": [ - { - "name": "Invoke Reject Application Function", - "functionRef": "RejectApplication" - } - ], - "transition": "SendBackResults" - }, - { - "name": "SendBackResults", - "type": "operation", - "actions": [ - { - "name": "SendBackResultsOperation", - "functionRef": "SendBackResultsFunction" - } - ], - "end": true - } - ], - "functions": [ - { - "name": "ApproveApplication", - "type": "rest" - }, - { - "name": "RejectApplication", - "type": "rest" - }, - { - "name": "SendBackResultsFunction", - "type": "custom", - "operation": "applicantworkflow#CustomerDecision" - } - ], - "events": [ - { - "name": "ToApproveCustomer", - "type": "com.fasterxml.jackson.databind.JsonNode", - "source": "applicationsSource" - }, - { - "name": "ApprovalDecision", - "type": "com.fasterxml.jackson.databind.JsonNode", - "source": "applicationsSource" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/dsl/sampleflow.json b/core/src/main/resources/dsl/sampleflow.json new file mode 100644 index 000000000..387b7dc07 --- /dev/null +++ b/core/src/main/resources/dsl/sampleflow.json @@ -0,0 +1,27 @@ +{ + "id": "sampleFlow", + "name": "Sample Flow One", + "description": "Sample Flow Definition", + "actions": [ + { + "action": "One", + "retries": 10, + "startToCloseSec": 3 + }, + { + "action": "Two", + "retries": 8, + "startToCloseSec": 3 + }, + { + "action": "Three", + "retries": 10, + "startToCloseSec": 4 + }, + { + "action": "Four", + "retries": 9, + "startToCloseSec": 5 + } + ] +} \ No newline at end of file diff --git a/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java b/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java index f676e48ef..808504a3f 100644 --- a/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java @@ -21,17 +21,10 @@ import static org.junit.Assert.*; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import io.serverlessworkflow.api.Workflow; import io.temporal.client.WorkflowOptions; -import io.temporal.client.WorkflowStub; +import io.temporal.samples.dsl.model.Flow; import io.temporal.testing.TestWorkflowRule; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import org.junit.Rule; import org.junit.Test; @@ -40,79 +33,38 @@ public class DslWorkflowTest { @Rule public TestWorkflowRule testWorkflowRule = TestWorkflowRule.newBuilder() - .setWorkflowTypes(DynamicDslWorkflow.class) + .setWorkflowTypes(DslWorkflowImpl.class) .setActivityImplementations(new DslActivitiesImpl()) .build(); @Test - public void testCustomerApplicationDSLWorkflow() throws Exception { - Workflow dslWorkflow = DslWorkflowCache.getWorkflow("customerapplication", "1.0"); - - WorkflowOptions workflowOptions = - WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build(); - - WorkflowStub workflow = - testWorkflowRule - .getWorkflowClient() - .newUntypedWorkflowStub(dslWorkflow.getName(), workflowOptions); - - workflow.start( - dslWorkflow.getId(), - dslWorkflow.getVersion(), - getSampleWorkflowInput("dsl/customerapplication/datainput.json")); - - JsonNode result = workflow.getResult(JsonNode.class); - - assertNotNull(result); - assertNotNull(result.get("customer")); - assertNotNull(result.get("results")); - ArrayNode results = (ArrayNode) result.get("results"); - assertNotNull(results); - assertEquals(3, results.size()); - assertEquals("APPROVED", results.get(2).get("result").asText()); - } - - @Test - public void testBankingTransactionsDSLWorkflow() throws Exception { - Workflow dslWorkflow = DslWorkflowCache.getWorkflow("bankingtransactions", "1.0"); - - WorkflowOptions workflowOptions = - WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build(); - - WorkflowStub workflow = + public void testDslWorkflow() throws Exception { + DslWorkflow workflow = testWorkflowRule + .getTestEnvironment() .getWorkflowClient() - .newUntypedWorkflowStub(dslWorkflow.getName(), workflowOptions); - - workflow.start( - dslWorkflow.getId(), - dslWorkflow.getVersion(), - getSampleWorkflowInput("dsl/bankingtransactions/datainput.json")); - - JsonNode result = workflow.getResult(JsonNode.class); - + .newWorkflowStub( + DslWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId("dsl-workflow") + .setTaskQueue(testWorkflowRule.getWorker().getTaskQueue()) + .build()); + + String result = workflow.run(getFlowFromResource(), "test input"); assertNotNull(result); - assertNotNull(result.get("customer")); - assertNotNull(result.get("results")); - ArrayNode results = (ArrayNode) result.get("results"); - assertNotNull(results); - assertEquals(3, results.size()); - assertEquals("InvokeBankingService", results.get(0).get("type").asText()); - assertEquals("invoked", results.get(0).get("result").asText()); - assertEquals("InvokeBankingService", results.get(1).get("type").asText()); - assertEquals("invoked", results.get(1).get("result").asText()); - assertEquals("InvokeBankingService", results.get(2).get("type").asText()); - assertEquals("invoked", results.get(2).get("result").asText()); + assertEquals( + "Activity one done...,Activity two done...,Activity three done...,Activity four done...", + result); } - private static JsonNode getSampleWorkflowInput(String dataInputFileName) throws Exception { - String workflowDataInput = getFileAsString(dataInputFileName); + private static Flow getFlowFromResource() { ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readTree(workflowDataInput); - } - - private static String getFileAsString(String fileName) throws IOException { - File file = new File(DslWorkflowTest.class.getClassLoader().getResource(fileName).getFile()); - return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); + try { + return objectMapper.readValue( + DslWorkflowTest.class.getClassLoader().getResource("dsl/sampleflow.json"), Flow.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } } } diff --git a/core/src/test/resources/dsl/bankingtransactions/datainput.json b/core/src/test/resources/dsl/bankingtransactions/datainput.json deleted file mode 100644 index 8fee3af06..000000000 --- a/core/src/test/resources/dsl/bankingtransactions/datainput.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "customer": { - "name": "John", - "age": 22, - "transactions": [100, -50, 20] - }, - "results": [] -} \ No newline at end of file diff --git a/core/src/test/resources/dsl/bankingtransactions/workflow.json b/core/src/test/resources/dsl/bankingtransactions/workflow.json deleted file mode 100644 index a510178c8..000000000 --- a/core/src/test/resources/dsl/bankingtransactions/workflow.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "id": "bankingtransactions", - "name": "Customer Banking Transactions Workflow", - "version": "1.0", - "specVersion": "0.8", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1M" - }, - "actionExecTimeout": "PT10S" - }, - "autoRetries": true, - "start": "ProcessTransactions", - "states": [ - { - "name": "ProcessTransactions", - "type": "foreach", - "inputCollection": "${ .customer.transactions }", - "iterationParam": "${ .tx }", - "mode": "parallel", - "actions": [ - { - "name": "Processing Action", - "functionRef": "InvokeBankingService" - } - ], - "end": true - } - ], - "functions": [ - { - "name": "InvokeBankingService", - "type": "rest" - }, - { - "name": "QueryCustomerName", - "type": "expression", - "operation": "${ .customer.name }" - }, - { - "name": "QueryCustomerAge", - "type": "expression", - "operation": "${ .customer.age }" - } - ] -} \ No newline at end of file diff --git a/core/src/test/resources/dsl/bankingtransactions/workflow.yml b/core/src/test/resources/dsl/bankingtransactions/workflow.yml deleted file mode 100644 index b1fb45f4d..000000000 --- a/core/src/test/resources/dsl/bankingtransactions/workflow.yml +++ /dev/null @@ -1,29 +0,0 @@ -id: bankingtransactions -name: Customer Banking Transactions Workflow -version: '1.0' -specVersion: '0.8' -timeouts: - workflowExecTimeout: - duration: PT1M - actionExecTimeout: PT10S -autoRetries: true -start: ProcessTransactions -states: - - name: ProcessTransactions - type: foreach - inputCollection: "${ .customer.transactions }" - iterationParam: "${ .tx }" - mode: parallel - actions: - - name: Processing Action - functionRef: InvokeBankingService - end: true -functions: - - name: InvokeBankingService - type: rest - - name: QueryCustomerName - type: expression - operation: "${ .customer.name }" - - name: QueryCustomerAge - type: expression - operation: "${ .customer.age }" diff --git a/core/src/test/resources/dsl/customerapplication/datainput.json b/core/src/test/resources/dsl/customerapplication/datainput.json deleted file mode 100644 index 19f754c37..000000000 --- a/core/src/test/resources/dsl/customerapplication/datainput.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "customer": { - "name": "John", - "age": 22 - }, - "results": [] -} \ No newline at end of file diff --git a/core/src/test/resources/dsl/customerapplication/workflow.json b/core/src/test/resources/dsl/customerapplication/workflow.json deleted file mode 100644 index 6b099c8f9..000000000 --- a/core/src/test/resources/dsl/customerapplication/workflow.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "id": "customerapplication", - "name": "Customer Application Workflow", - "version": "1.0", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1M" - }, - "actionExecTimeout": "PT10S" - }, - "retries": [ - { - "name": "WorkflowRetries", - "delay": "PT3S", - "maxAttempts": 10 - } - ], - "states": [ - { - "name": "NewCustomerApplication", - "type": "event", - "onEvents": [{ - "eventRefs": ["NewApplicationEvent"], - "actionMode": "parallel", - "actions":[ - { - "name": "Invoke Check Customer Info Function", - "functionRef": "CheckCustomerInfo" - }, - { - "name": "Invoke Update Application Info Function", - "functionRef": "UpdateApplicationInfo" - } - ] - }], - "transition": "MakeApplicationDecision" - }, - { - "name": "MakeApplicationDecision", - "type": "switch", - "dataConditions": [ - { - "condition": "${ .customer.age >= 20 }", - "transition": "ApproveApplication" - }, - { - "condition": "${ .customer.age < 20 }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "ApproveApplication", - "type": "operation", - "actions": [ - { - "name": "Invoke Approve Application Function", - "functionRef": "ApproveApplication", - "sleep": { - "before": "PT1S" - } - } - ], - "end": true - }, - { - "name": "RejectApplication", - "type": "operation", - "actions": [ - { - "name": "Invoke Reject Application Function", - "functionRef": "RejectApplication", - "sleep": { - "before": "PT1S" - } - } - ], - "end": true - } - ], - "functions": [ - { - "name": "CheckCustomerInfo", - "type": "rest" - }, - { - "name": "UpdateApplicationInfo", - "type": "rest" - }, - { - "name": "ApproveApplication", - "type": "rest" - }, - { - "name": "RejectApplication", - "type": "rest" - }, - { - "name": "QueryCustomerName", - "type": "expression", - "operation": "${ .customer.name }" - }, - { - "name": "QueryCustomerAge", - "type": "expression", - "operation": "${ .customer.age }" - } - ], - "events": [ - { - "name": "NewApplicationEvent", - "type": "com.fasterxml.jackson.databind.JsonNode", - "source": "applicationsSource" - } - ] -} \ No newline at end of file diff --git a/core/src/test/resources/dsl/customerapplication/workflow.yml b/core/src/test/resources/dsl/customerapplication/workflow.yml deleted file mode 100644 index 996c5376a..000000000 --- a/core/src/test/resources/dsl/customerapplication/workflow.yml +++ /dev/null @@ -1,68 +0,0 @@ -id: customerapplication -name: Customer Application Workflow -version: '1.0' -timeouts: - workflowExecTimeout: - duration: PT1M - actionExecTimeout: PT10S -retries: - - name: WorkflowRetries - delay: PT3S - maxAttempts: 10 -states: - - name: NewCustomerApplication - type: event - onEvents: - - eventRefs: - - NewApplicationEvent - actionMode: parallel - actions: - - name: Invoke Check Customer Info Function - functionRef: CheckCustomerInfo - - name: Invoke Update Application Info Function - functionRef: UpdateApplicationInfo - transition: MakeApplicationDecision - - name: MakeApplicationDecision - type: switch - dataConditions: - - condition: "${ .customer.age >= 20 }" - transition: ApproveApplication - - condition: "${ .customer.age < 20 }" - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: ApproveApplication - type: operation - actions: - - name: Invoke Approve Application Function - functionRef: ApproveApplication - sleep: - before: PT1S - end: true - - name: RejectApplication - type: operation - actions: - - name: Invoke Reject Application Function - functionRef: RejectApplication - sleep: - before: PT1S - end: true -functions: - - name: CheckCustomerInfo - type: rest - - name: UpdateApplicationInfo - type: rest - - name: ApproveApplication - type: rest - - name: RejectApplication - type: rest - - name: QueryCustomerName - type: expression - operation: "${ .customer.name }" - - name: QueryCustomerAge - type: expression - operation: "${ .customer.age }" -events: - - name: NewApplicationEvent - type: com.fasterxml.jackson.databind.JsonNode - source: applicationsSource diff --git a/core/src/test/resources/dsl/sampleflow.json b/core/src/test/resources/dsl/sampleflow.json new file mode 100644 index 000000000..387b7dc07 --- /dev/null +++ b/core/src/test/resources/dsl/sampleflow.json @@ -0,0 +1,27 @@ +{ + "id": "sampleFlow", + "name": "Sample Flow One", + "description": "Sample Flow Definition", + "actions": [ + { + "action": "One", + "retries": 10, + "startToCloseSec": 3 + }, + { + "action": "Two", + "retries": 8, + "startToCloseSec": 3 + }, + { + "action": "Three", + "retries": 10, + "startToCloseSec": 4 + }, + { + "action": "Four", + "retries": 9, + "startToCloseSec": 5 + } + ] +} \ No newline at end of file From e7db2a10542a67b1962dd711ce7621c9832b0e45 Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Fri, 26 Jul 2024 11:11:20 -0400 Subject: [PATCH 187/240] Fix SAGA samples (#655) --- .../temporal/samples/bookingsaga/TripBookingWorker.java | 9 ++------- .../samples/bookingsyncsaga/TripBookingWorker.java | 6 ++---- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java index d0dd532d6..abfe004a9 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java @@ -20,17 +20,12 @@ package io.temporal.samples.bookingsaga; import io.temporal.client.WorkflowClient; -import io.temporal.samples.bookingsyncsaga.TripBookingActivities; -import io.temporal.samples.bookingsyncsaga.TripBookingActivitiesImpl; -import io.temporal.samples.bookingsyncsaga.TripBookingWorkflowImpl; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; public class TripBookingWorker { - static final String TASK_QUEUE = "TripBooking"; - @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { // gRPC stubs wrapper that talks to the local docker instance of temporal service. @@ -42,7 +37,7 @@ public static void main(String[] args) { WorkerFactory factory = WorkerFactory.newInstance(client); // Worker that listens on a task queue and hosts both workflow and activity implementations. - Worker worker = factory.newWorker(TASK_QUEUE); + Worker worker = factory.newWorker(TripBookingClient.TASK_QUEUE); // Workflows are stateful. So you need a type to create instances. worker.registerWorkflowImplementationTypes(TripBookingWorkflowImpl.class); @@ -53,6 +48,6 @@ public static void main(String[] args) { // Start all workers created by this factory. factory.start(); - System.out.println("Worker started for task queue: " + TASK_QUEUE); + System.out.println("Worker started for task queue: " + TripBookingClient.TASK_QUEUE); } } diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java index 035c1859e..263d4e405 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java @@ -26,8 +26,6 @@ public class TripBookingWorker { - static final String TASK_QUEUE = "TripBooking"; - @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { // gRPC stubs wrapper that talks to the local docker instance of temporal service. @@ -39,7 +37,7 @@ public static void main(String[] args) { WorkerFactory factory = WorkerFactory.newInstance(client); // Worker that listens on a task queue and hosts both workflow and activity implementations. - Worker worker = factory.newWorker(TASK_QUEUE); + Worker worker = factory.newWorker(TripBookingClient.TASK_QUEUE); // Workflows are stateful. So you need a type to create instances. worker.registerWorkflowImplementationTypes(TripBookingWorkflowImpl.class); @@ -50,6 +48,6 @@ public static void main(String[] args) { // Start all workers created by this factory. factory.start(); - System.out.println("Worker started for task queue: " + TASK_QUEUE); + System.out.println("Worker started for task queue: " + TripBookingClient.TASK_QUEUE); } } From f239fabb92921cd677648c856f49d013a74d67ee Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Wed, 7 Aug 2024 19:04:53 -0400 Subject: [PATCH 188/240] Sample - exclude workflow/activity types from interceptors (#658) * Sample - exclude workflow/activity types from interceptors Signed-off-by: Tihomir Surdilovic * changed activity check event type in test Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 4 +- .../samples/excludefrominterceptor/README.md | 15 +++ .../RunMyWorkflows.java | 96 +++++++++++++++ .../activities/ForInterceptorActivities.java | 29 +++++ .../ForInterceptorActivitiesImpl.java | 28 +++++ .../activities/MyActivities.java | 29 +++++ .../activities/MyActivitiesImpl.java | 28 +++++ .../MyActivityInboundCallsInterceptor.java | 64 ++++++++++ .../interceptor/MyWorkerInterceptor.java | 52 ++++++++ .../MyWorkflowInboundCallsInterceptor.java | 67 ++++++++++ .../MyWorkflowOutboundCallsInterceptor.java | 58 +++++++++ .../workflows/MyWorkflow.java | 27 ++++ .../workflows/MyWorkflowOne.java | 25 ++++ .../workflows/MyWorkflowOneImpl.java | 40 ++++++ .../workflows/MyWorkflowTwo.java | 25 ++++ .../workflows/MyWorkflowTwoImpl.java | 40 ++++++ .../ExcludeFromInterceptorTest.java | 115 ++++++++++++++++++ 17 files changed, 741 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/README.md create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyActivityInboundCallsInterceptor.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowInboundCallsInterceptor.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowOutboundCallsInterceptor.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java create mode 100644 core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java create mode 100644 core/src/test/java/io/temporal/samples/excludefrominterceptor/ExcludeFromInterceptorTest.java diff --git a/README.md b/README.md index 3b271dec0..77c00a4e5 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Updatable Timer**](/core/src/main/java/io/temporal/samples/updatabletimer): Demonstrates the use of a helper class which relies on `Workflow.await` to implement a blocking sleep that can be updated at any moment. - [**Workflow Count Interceptor**](/core/src/main/java/io/temporal/samples/countinterceptor): Demonstrates how to create and register a simple Workflow Count Interceptor. -- + - [**Workflow Retry On Signal Interceptor**](/core/src/main/java/io/temporal/samples/retryonsignalinterceptor): Demonstrates how to create and register an interceptor that retries an activity on a signal. - [**List Workflows**](/core/src/main/java/io/temporal/samples/listworkflows): Demonstrates the use of custom search attributes and ListWorkflowExecutionsRequest with custom queries. @@ -129,6 +129,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Payload Codec**](/core/src/main/java/io/temporal/samples/encodefailures): Demonstrates how to use simple codec to encode/decode failure messages. +- [**Exclude Workflow/ActivityTypes from Interceptors**](/core/src/main/java/io/temporal/samples/excludefrominterceptor): Demonstrates how to exclude certain workflow / activity types from interceptors. + #### SDK Metrics - [**Set up SDK metrics**](/core/src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics. diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/README.md b/core/src/main/java/io/temporal/samples/excludefrominterceptor/README.md new file mode 100644 index 000000000..538c46f11 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/README.md @@ -0,0 +1,15 @@ +# Excluding certain Workflow and Activity Types from interceptors + +This sample shows how to exclude certain workflow types and Activity types from Workflow and Activity Interceptors. + +1. Start the Sample: +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.excludefrominterceptor.RunMyWorkflows +``` + +Observe the event histories of MyWorkflowOne and MyWorkflowTwo in your Temporal Web UI. +You should see that even tho both executions were served by same worker so both had the interceptors applied, +MyWorkflowTwo was excluded from being applied by these interceptors. + +Also from the Activity interceptor logs (System.out prints during sample run) note that +only ActivityOne activity is being intercepted and not ActivityTwo or the "ForInterceptor" activities. diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java new file mode 100644 index 000000000..164b4972d --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.samples.excludefrominterceptor.activities.ForInterceptorActivitiesImpl; +import io.temporal.samples.excludefrominterceptor.activities.MyActivitiesImpl; +import io.temporal.samples.excludefrominterceptor.interceptor.MyWorkerInterceptor; +import io.temporal.samples.excludefrominterceptor.workflows.*; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerFactoryOptions; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; + +public class RunMyWorkflows { + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkerFactoryOptions wfo = + WorkerFactoryOptions.newBuilder() + // exclude MyWorkflowTwo from interceptor + .setWorkerInterceptors( + new MyWorkerInterceptor( + // exclude MyWorkflowTwo from workflow interceptors + Arrays.asList(MyWorkflowTwo.class.getSimpleName()), + // exclude ActivityTwo and the "ForInterceptor" activities from activity + // interceptor + // note with SpringBoot starter you could use bean names here, we use strings to + // not have + // to reflect on the activity impl class in sample + Arrays.asList( + "ActivityTwo", "ForInterceptorActivityOne", "ForInterceptorActivityTwo"))) + .validateAndBuildWithDefaults(); + + WorkerFactory factory = WorkerFactory.newInstance(client, wfo); + Worker worker = factory.newWorker("exclude-from-interceptor-queue"); + worker.registerWorkflowImplementationTypes(MyWorkflowOneImpl.class, MyWorkflowTwoImpl.class); + worker.registerActivitiesImplementations( + new MyActivitiesImpl(), new ForInterceptorActivitiesImpl()); + + factory.start(); + + MyWorkflow myWorkflow = + client.newWorkflowStub( + MyWorkflowOne.class, + WorkflowOptions.newBuilder() + .setWorkflowId("MyWorkflowOne") + .setTaskQueue("exclude-from-interceptor-queue") + .build()); + + MyWorkflowTwo myWorkflowTwo = + client.newWorkflowStub( + MyWorkflowTwo.class, + WorkflowOptions.newBuilder() + .setWorkflowId("MyWorkflowTwo") + .setTaskQueue("exclude-from-interceptor-queue") + .build()); + + WorkflowClient.start(myWorkflow::execute, "my workflow input"); + WorkflowClient.start(myWorkflowTwo::execute, "my workflow two input"); + + // wait for both execs to complete + try { + CompletableFuture.allOf( + WorkflowStub.fromTyped(myWorkflow).getResultAsync(String.class), + WorkflowStub.fromTyped(myWorkflowTwo).getResultAsync(String.class)) + .get(); + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + } + + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java new file mode 100644 index 000000000..118cd7279 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.activities; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface ForInterceptorActivities { + void forInterceptorActivityOne(Object output); + + void forInterceptorActivityTwo(Object output); +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java new file mode 100644 index 000000000..1d5fc7025 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.activities; + +public class ForInterceptorActivitiesImpl implements ForInterceptorActivities { + @Override + public void forInterceptorActivityOne(Object output) {} + + @Override + public void forInterceptorActivityTwo(Object output) {} +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java new file mode 100644 index 000000000..106916fc8 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.activities; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface MyActivities { + void activityOne(String input); + + void activityTwo(String input); +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java new file mode 100644 index 000000000..48fe29a86 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.activities; + +public class MyActivitiesImpl implements MyActivities { + @Override + public void activityOne(String input) {} + + @Override + public void activityTwo(String input) {} +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyActivityInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyActivityInboundCallsInterceptor.java new file mode 100644 index 000000000..69c79429a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyActivityInboundCallsInterceptor.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.interceptor; + +import io.temporal.activity.ActivityExecutionContext; +import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; +import io.temporal.common.interceptors.ActivityInboundCallsInterceptorBase; +import java.util.ArrayList; +import java.util.List; + +public class MyActivityInboundCallsInterceptor extends ActivityInboundCallsInterceptorBase { + + private ActivityExecutionContext activityExecutionContext; + private List excludeActivityTypes = new ArrayList<>(); + + public MyActivityInboundCallsInterceptor(ActivityInboundCallsInterceptor next) { + super(next); + } + + public MyActivityInboundCallsInterceptor( + List excludeActivityTypes, ActivityInboundCallsInterceptor next) { + super(next); + this.excludeActivityTypes = excludeActivityTypes; + } + + @Override + public void init(ActivityExecutionContext context) { + this.activityExecutionContext = context; + super.init(context); + } + + @Override + public ActivityOutput execute(ActivityInput input) { + if (!excludeActivityTypes.contains(activityExecutionContext.getInfo().getActivityType())) { + // If activity retry attempt is > X then we want to log this (or push to metrics or similar) + // for demo we just use >=1 just to log and dont have to explicitly fail our sample activities + if (activityExecutionContext.getInfo().getAttempt() >= 1) { + System.out.println( + "Activity retry attempt noted - " + + activityExecutionContext.getInfo().getWorkflowType() + + " - " + + activityExecutionContext.getInfo().getActivityType()); + } + } + return super.execute(input); + } +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java new file mode 100644 index 000000000..7674013dc --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.interceptor; + +import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; +import io.temporal.common.interceptors.WorkerInterceptor; +import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; +import java.util.ArrayList; +import java.util.List; + +public class MyWorkerInterceptor implements WorkerInterceptor { + private List excludeWorkflowTypes = new ArrayList<>(); + private List excludeActivityTypes = new ArrayList<>(); + + public MyWorkerInterceptor() {} + + public MyWorkerInterceptor(List excludeWorkflowTypes) { + this.excludeWorkflowTypes = excludeWorkflowTypes; + } + + public MyWorkerInterceptor(List excludeWorkflowTypes, List excludeActivityTypes) { + this.excludeWorkflowTypes = excludeWorkflowTypes; + this.excludeActivityTypes = excludeActivityTypes; + } + + @Override + public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) { + return new MyWorkflowInboundCallsInterceptor(excludeWorkflowTypes, next); + } + + @Override + public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) { + return new MyActivityInboundCallsInterceptor(excludeActivityTypes, next); + } +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowInboundCallsInterceptor.java new file mode 100644 index 000000000..023a098bf --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowInboundCallsInterceptor.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.interceptor; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; +import io.temporal.common.interceptors.WorkflowInboundCallsInterceptorBase; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; +import io.temporal.samples.excludefrominterceptor.activities.ForInterceptorActivities; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInfo; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +public class MyWorkflowInboundCallsInterceptor extends WorkflowInboundCallsInterceptorBase { + private WorkflowInfo workflowInfo; + private List excludeWorkflowTypes = new ArrayList<>(); + private ForInterceptorActivities activities = + Workflow.newActivityStub( + ForInterceptorActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + public MyWorkflowInboundCallsInterceptor(WorkflowInboundCallsInterceptor next) { + super(next); + } + + public MyWorkflowInboundCallsInterceptor( + List excludeWorkflowTypes, WorkflowInboundCallsInterceptor next) { + super(next); + this.excludeWorkflowTypes = excludeWorkflowTypes; + } + + @Override + public void init(WorkflowOutboundCallsInterceptor outboundCalls) { + this.workflowInfo = Workflow.getInfo(); + super.init(new MyWorkflowOutboundCallsInterceptor(excludeWorkflowTypes, outboundCalls)); + } + + @Override + public WorkflowOutput execute(WorkflowInput input) { + WorkflowOutput output = super.execute(input); + if (!excludeWorkflowTypes.contains(workflowInfo.getWorkflowType())) { + // After workflow completes we want to execute activity to lets say persist its result to db + // or similar + activities.forInterceptorActivityOne(output.getResult()); + } + return output; + } +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowOutboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowOutboundCallsInterceptor.java new file mode 100644 index 000000000..9d99acb8a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowOutboundCallsInterceptor.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.interceptor; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptorBase; +import io.temporal.samples.excludefrominterceptor.activities.ForInterceptorActivities; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +public class MyWorkflowOutboundCallsInterceptor extends WorkflowOutboundCallsInterceptorBase { + private List excludeWorkflowTypes = new ArrayList<>(); + private ForInterceptorActivities activities = + Workflow.newActivityStub( + ForInterceptorActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + public MyWorkflowOutboundCallsInterceptor(WorkflowOutboundCallsInterceptor next) { + super(next); + } + + public MyWorkflowOutboundCallsInterceptor( + List excludeWorkflowTypes, WorkflowOutboundCallsInterceptor next) { + super(next); + this.excludeWorkflowTypes = excludeWorkflowTypes; + } + + @Override + public ActivityOutput executeActivity(ActivityInput input) { + ActivityOutput output = super.executeActivity(input); + if (!excludeWorkflowTypes.contains(Workflow.getInfo().getWorkflowType())) { + // After activity completes we want to execute activity to lets say persist its result to db + // or similar + activities.forInterceptorActivityTwo(output.getResult().get()); + } + return output; + } +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java new file mode 100644 index 000000000..6c334f97a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.workflows; + +import io.temporal.workflow.WorkflowMethod; + +public interface MyWorkflow { + @WorkflowMethod + String execute(String input); +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java new file mode 100644 index 000000000..d7be4d3d0 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.workflows; + +import io.temporal.workflow.WorkflowInterface; + +@WorkflowInterface +public interface MyWorkflowOne extends MyWorkflow {} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java new file mode 100644 index 000000000..1409bce40 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.workflows; + +import io.temporal.activity.ActivityOptions; +import io.temporal.samples.excludefrominterceptor.activities.MyActivities; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class MyWorkflowOneImpl implements MyWorkflowOne { + private MyActivities activities = + Workflow.newActivityStub( + MyActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String execute(String input) { + activities.activityOne(input); + activities.activityTwo(input); + + return "done"; + } +} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java new file mode 100644 index 000000000..07d6b8dc6 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.workflows; + +import io.temporal.workflow.WorkflowInterface; + +@WorkflowInterface +public interface MyWorkflowTwo extends MyWorkflow {} diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java new file mode 100644 index 000000000..e4b012b99 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor.workflows; + +import io.temporal.activity.ActivityOptions; +import io.temporal.samples.excludefrominterceptor.activities.MyActivities; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class MyWorkflowTwoImpl implements MyWorkflowTwo { + private MyActivities activities = + Workflow.newActivityStub( + MyActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String execute(String input) { + activities.activityOne(input); + activities.activityTwo(input); + + return "done"; + } +} diff --git a/core/src/test/java/io/temporal/samples/excludefrominterceptor/ExcludeFromInterceptorTest.java b/core/src/test/java/io/temporal/samples/excludefrominterceptor/ExcludeFromInterceptorTest.java new file mode 100644 index 000000000..d77b6e41c --- /dev/null +++ b/core/src/test/java/io/temporal/samples/excludefrominterceptor/ExcludeFromInterceptorTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.excludefrominterceptor; + +import io.temporal.api.enums.v1.EventType; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.common.WorkflowExecutionHistory; +import io.temporal.samples.excludefrominterceptor.activities.ForInterceptorActivitiesImpl; +import io.temporal.samples.excludefrominterceptor.activities.MyActivitiesImpl; +import io.temporal.samples.excludefrominterceptor.interceptor.MyWorkerInterceptor; +import io.temporal.samples.excludefrominterceptor.workflows.*; +import io.temporal.testing.TestWorkflowRule; +import io.temporal.worker.WorkerFactoryOptions; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ExcludeFromInterceptorTest { + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(MyWorkflowOneImpl.class, MyWorkflowTwoImpl.class) + .setActivityImplementations(new MyActivitiesImpl(), new ForInterceptorActivitiesImpl()) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors( + new MyWorkerInterceptor( + // exclude MyWorkflowTwo from workflow interceptors + Arrays.asList(MyWorkflowTwo.class.getSimpleName()), + // exclude ActivityTwo and the "ForInterceptor" activities from activity + // interceptor + // note with SpringBoot starter you could use bean names here, we use + // strings to + // not have + // to reflect on the activity impl class in sample + Arrays.asList( + "ActivityTwo", + "ForInterceptorActivityOne", + "ForInterceptorActivityTwo"))) + .build()) + .build(); + + @Test + public void testExcludeFromInterceptor() { + MyWorkflow myWorkflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + MyWorkflowOne.class, + WorkflowOptions.newBuilder() + .setWorkflowId("MyWorkflowOne") + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build()); + + MyWorkflowTwo myWorkflowTwo = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + MyWorkflowTwo.class, + WorkflowOptions.newBuilder() + .setWorkflowId("MyWorkflowTwo") + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build()); + + WorkflowClient.start(myWorkflow::execute, "my workflow input"); + WorkflowClient.start(myWorkflowTwo::execute, "my workflow two input"); + + // wait for both execs to complete + try { + CompletableFuture.allOf( + WorkflowStub.fromTyped(myWorkflow).getResultAsync(String.class), + WorkflowStub.fromTyped(myWorkflowTwo).getResultAsync(String.class)) + .get(); + } catch (Exception e) { + Assert.fail("Exception executing workflows: " + e.getMessage()); + } + + Assert.assertEquals(5, getNumOfActivitiesForExec("MyWorkflowOne")); + Assert.assertEquals(2, getNumOfActivitiesForExec("MyWorkflowTwo")); + } + + private int getNumOfActivitiesForExec(String workflowId) { + WorkflowExecutionHistory history = + testWorkflowRule.getWorkflowClient().fetchHistory(workflowId); + int counter = 0; + for (HistoryEvent event : history.getEvents()) { + if (event.getEventType().equals(EventType.EVENT_TYPE_ACTIVITY_TASK_COMPLETED)) { + counter++; + } + } + return counter; + } +} From bcdc8db8f122de9c10b277c6248eabd473032fe7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 23:28:54 -0400 Subject: [PATCH 189/240] Bump javaSDKVersion from 1.24.1 to 1.24.3 (#657) Bumps `javaSDKVersion` from 1.24.1 to 1.24.3. Updates `io.temporal:temporal-sdk` from 1.24.1 to 1.24.3 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.24.1...v1.24.3) Updates `io.temporal:temporal-opentracing` from 1.24.1 to 1.24.3 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.24.1...v1.24.3) Updates `io.temporal:temporal-testing` from 1.24.1 to 1.24.3 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.24.1...v1.24.3) Updates `io.temporal:temporal-spring-boot-starter` from 1.24.1 to 1.24.3 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.24.1...v1.24.3) --- updated-dependencies: - dependency-name: io.temporal:temporal-sdk dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-opentracing dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-testing dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.temporal:temporal-spring-boot-starter dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a4a6c7142..972142f5b 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.24.1' + javaSDKVersion = '1.24.3' camelVersion = '3.22.1' jarVersion = '1.0.0' } From 9ee3ddd42955ebde6e29542517d12a5365d05f56 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 13 Aug 2024 08:04:32 -0700 Subject: [PATCH 190/240] Switch to github actions for CI (#659) Switch to github actions for CI --- .buildkite/pipeline.yml | 24 --------- .github/workflows/ci.yml | 50 +++++++++++++++++++ .../workflows/gradle-wrapper-validation.yml | 10 ---- docker/buildkite/README.md | 19 ------- docker/buildkite/copyright-and-code-format.sh | 11 ---- docker/{buildkite => github}/Dockerfile | 0 docker/github/README.md | 17 +++++++ .../{buildkite => github}/docker-compose.yaml | 2 +- 8 files changed, 68 insertions(+), 65 deletions(-) delete mode 100644 .buildkite/pipeline.yml create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/gradle-wrapper-validation.yml delete mode 100644 docker/buildkite/README.md delete mode 100755 docker/buildkite/copyright-and-code-format.sh rename docker/{buildkite => github}/Dockerfile (100%) create mode 100644 docker/github/README.md rename docker/{buildkite => github}/docker-compose.yaml (81%) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml deleted file mode 100644 index 4016cf369..000000000 --- a/.buildkite/pipeline.yml +++ /dev/null @@ -1,24 +0,0 @@ -steps: - - label: ":java: Unit test" - agents: - queue: "default" - docker: "*" - command: "./gradlew --no-daemon test" - timeout_in_minutes: 15 - plugins: - - docker-compose#v3.0.0: - run: unit-test - config: docker/buildkite/docker-compose.yaml - - - label: ":copyright: Copyright and code format" - agents: - queue: "default" - docker: "*" - command: "docker/buildkite/copyright-and-code-format.sh" - timeout_in_minutes: 15 - plugins: - - docker-compose#v3.8.0: - run: unit-test - config: docker/buildkite/docker-compose.yaml - - - wait diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..3e2e0df58 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +name: "Continuous Integration" +on: [push, pull_request] + +jobs: + validation: + name: "Gradle wrapper validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: gradle/wrapper-validation-action@v3 + + unittest: + name: Unit Tests + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + ref: ${{ github.event.pull_request.head.sha }} + + - name: Run unit tests + run: | + docker compose -f ./docker/github/docker-compose.yaml up unit-test + + copyright: + name: Copyright and code format + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + ref: ${{ github.event.pull_request.head.sha }} + + - name: Set up Java + uses: actions/setup-java@v4 + with: + java-version: "11" + distribution: "temurin" + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Run copyright and code format checks + run: ./gradlew --no-daemon checkLicenseMain checkLicenses spotlessCheck \ No newline at end of file diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml deleted file mode 100644 index eb00f93cd..000000000 --- a/.github/workflows/gradle-wrapper-validation.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: "Validate Gradle Wrapper" -on: [push, pull_request] - -jobs: - validation: - name: "Gradle wrapper validation" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v3 diff --git a/docker/buildkite/README.md b/docker/buildkite/README.md deleted file mode 100644 index 42153a4ed..000000000 --- a/docker/buildkite/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Using BuildKite - -BuildKite simply runs Docker containers. So it is easy to perform the -same build locally that BuildKite will do. To handle this, there are -two different docker-compose files: one for BuildKite and one for local. -The Dockerfile is the same for both. - -## Testing the build locally -To run the build locally, start from the root folder of this repo and run the following command: -```bash -docker-compose -f docker/buildkite/docker-compose.yaml run unit-test -``` - -Note that BuildKite will run basically the same commands. - -## Testing the build in BuildKite -Creating a PR against the main branch will trigger the BuildKite -build. Members of the Temporal team can view the build pipeline here: -https://buildkite.com/temporal/java-samples diff --git a/docker/buildkite/copyright-and-code-format.sh b/docker/buildkite/copyright-and-code-format.sh deleted file mode 100755 index f8ae826d3..000000000 --- a/docker/buildkite/copyright-and-code-format.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -xeou pipefail - -./gradlew --no-daemon check -x test - -if [ ! -z "$(git status --porcelain)" ]; then - echo 'Some files were improperly formatted. Please run build locally and check in all changes.' - git status; - exit 1; -fi - diff --git a/docker/buildkite/Dockerfile b/docker/github/Dockerfile similarity index 100% rename from docker/buildkite/Dockerfile rename to docker/github/Dockerfile diff --git a/docker/github/README.md b/docker/github/README.md new file mode 100644 index 000000000..608ad300d --- /dev/null +++ b/docker/github/README.md @@ -0,0 +1,17 @@ +# Using Github Actions + +Github action simply runs Docker containers. So it is easy to perform the +same build locally that Github will do. To handle this, there are +two different docker-compose files: one for Github and one for local. +The Dockerfile is the same for both. + +## Testing the build locally +To run the build locally, start from the root folder of this repo and run the following command: +```bash +docker-compose -f docker/github/docker-compose.yaml run unit-test +``` + +Note that Github action will run basically the same commands. + +## Testing the build in Github Actions +Creating a PR against the main branch will trigger the Github action. diff --git a/docker/buildkite/docker-compose.yaml b/docker/github/docker-compose.yaml similarity index 81% rename from docker/buildkite/docker-compose.yaml rename to docker/github/docker-compose.yaml index f19fbb834..6fafe73c9 100644 --- a/docker/buildkite/docker-compose.yaml +++ b/docker/github/docker-compose.yaml @@ -4,7 +4,7 @@ services: unit-test: build: context: ../../ - dockerfile: ./docker/buildkite/Dockerfile + dockerfile: ./docker/github/Dockerfile command: "./gradlew --no-daemon test" environment: - "USER=unittest" From 575d667880342228443842884f0f9b28431c991c Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Tue, 20 Aug 2024 20:41:18 -0400 Subject: [PATCH 191/240] Minor fix of workflow/worker confusion in comment (#663) --- .../src/main/java/io/temporal/samples/hello/HelloChild.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/hello/HelloChild.java b/core/src/main/java/io/temporal/samples/hello/HelloChild.java index 6ef6cdb67..a916c13c8 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloChild.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloChild.java @@ -133,13 +133,13 @@ public static void main(String[] args) { WorkflowClient client = WorkflowClient.newInstance(service); /* - * Define the workflow factory. It is used to create workflow workers for a specific task queue. + * Define the worker factory. It is used to create workers for a specific task queue. */ WorkerFactory factory = WorkerFactory.newInstance(client); /* - * Define the workflow worker. Workflow workers listen to a defined task queue and process - * workflows and activities. + * Define the worker. Workers listen to a defined task queue and process workflows and + * activities. */ Worker worker = factory.newWorker(TASK_QUEUE); From 67ca961a0d14025f3d97b6da278ef511af5ba0bf Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Mon, 26 Aug 2024 21:42:31 -0400 Subject: [PATCH 192/240] sample that shows how to set custom change version search attribute when using versioning api (#664) Signed-off-by: Tihomir Surdilovic --- .../CustomChangeVersionActivities.java | 31 ++++++ .../CustomChangeVersionActivitiesImpl.java | 37 +++++++ .../CustomChangeVersionStarter.java | 96 +++++++++++++++++++ .../CustomChangeVersionWorkflow.java | 29 ++++++ .../CustomChangeVersionWorkflowImpl.java | 72 ++++++++++++++ .../samples/customchangeversion/README.md | 19 ++++ 6 files changed, 284 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java create mode 100644 core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java create mode 100644 core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/customchangeversion/README.md diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java new file mode 100644 index 000000000..d42d0455f --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.customchangeversion; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface CustomChangeVersionActivities { + String customOne(String input); + + String customTwo(String input); + + String customThree(String input); +} diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java new file mode 100644 index 000000000..874171ff3 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.customchangeversion; + +public class CustomChangeVersionActivitiesImpl implements CustomChangeVersionActivities { + @Override + public String customOne(String input) { + return "\ncustomOne activity - " + input; + } + + @Override + public String customTwo(String input) { + return "\ncustomTwo activity - " + input; + } + + @Override + public String customThree(String input) { + return "\ncustomThree activity - " + input; + } +} diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java new file mode 100644 index 000000000..e1200360b --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.customchangeversion; + +import io.grpc.StatusRuntimeException; +import io.temporal.api.enums.v1.IndexedValueType; +import io.temporal.api.operatorservice.v1.AddSearchAttributesRequest; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowServiceException; +import io.temporal.common.SearchAttributeKey; +import io.temporal.common.SearchAttributes; +import io.temporal.serviceclient.OperatorServiceStubs; +import io.temporal.serviceclient.OperatorServiceStubsOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import java.util.Collections; + +public class CustomChangeVersionStarter { + private static SearchAttributeKey CUSTOM_CHANGE_VERSION = + SearchAttributeKey.forKeyword("CustomChangeVersion"); + private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + private static final WorkflowClient client = WorkflowClient.newInstance(service); + private static final String taskQueue = "customChangeVersionTaskQueue"; + private static final String workflowId = "CustomChangeVersionWorkflow"; + + public static void main(String[] args) { + WorkerFactory workerFactory = WorkerFactory.newInstance(client); + Worker worker = workerFactory.newWorker(taskQueue); + + // Register CustomChangeVersion search attribute thats used in this sample + OperatorServiceStubs operatorService = + OperatorServiceStubs.newServiceStubs( + OperatorServiceStubsOptions.newBuilder() + .setChannel(service.getRawChannel()) + .validateAndBuildWithDefaults()); + operatorService + .blockingStub() + .addSearchAttributes( + AddSearchAttributesRequest.newBuilder() + .setNamespace(client.getOptions().getNamespace()) + .putAllSearchAttributes( + Collections.singletonMap( + "CustomChangeVersion", IndexedValueType.INDEXED_VALUE_TYPE_KEYWORD)) + .build()); + + // Register workflow and activities + worker.registerWorkflowImplementationTypes(CustomChangeVersionWorkflowImpl.class); + worker.registerActivitiesImplementations(new CustomChangeVersionActivitiesImpl()); + workerFactory.start(); + + CustomChangeVersionWorkflow workflow = + client.newWorkflowStub( + CustomChangeVersionWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(taskQueue) + .setWorkflowId(workflowId) + .setTypedSearchAttributes( + SearchAttributes.newBuilder().set(CUSTOM_CHANGE_VERSION, "").build()) + .build()); + try { + String result = workflow.run("Hello"); + System.out.println("Result: " + result); + } catch (WorkflowServiceException e) { + if (e.getCause() instanceof StatusRuntimeException) { + StatusRuntimeException sre = (StatusRuntimeException) e.getCause(); + System.out.println( + "Error starting workflow execution: " + + sre.getMessage() + + " Status: " + + sre.getStatus()); + } else { + System.out.println("Error starting workflow execution: " + e.getMessage()); + } + } + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java new file mode 100644 index 000000000..20d090990 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.customchangeversion; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface CustomChangeVersionWorkflow { + @WorkflowMethod + String run(String input); +} diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflowImpl.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflowImpl.java new file mode 100644 index 000000000..51d3ca3eb --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflowImpl.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.customchangeversion; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.SearchAttributeKey; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +/** + * CustomChangeVersionWorkflowImpl shows how to upsert a custom search attribute which can be used + * when adding changes to our workflow using workflow versioning. Note that this is only temporary + * solution until https://github.com/temporalio/sdk-java/issues/587 is implemented. Given that a + * number of users are in need of this and are looking for a sample, we are adding this as sample + * until this issue is fixed, at which point it will no longer be needed. + */ +public class CustomChangeVersionWorkflowImpl implements CustomChangeVersionWorkflow { + static final SearchAttributeKey CUSTOM_CHANGE_VERSION = + SearchAttributeKey.forKeyword("CustomChangeVersion"); + private CustomChangeVersionActivities activities = + Workflow.newActivityStub( + CustomChangeVersionActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String run(String input) { + String result = activities.customOne(input); + // We assume when this change is added we have some executions of this workflow type running + // where customTwo activity was not called (we are adding it to exiting workflow) + // Adding customTwo activity as a versioned change + int version = Workflow.getVersion("add-v2-activity-change", Workflow.DEFAULT_VERSION, 1); + if (version == 1) { + // Upsert our custom change version search attribute + // We set its value to follow TemporalChangeVersion structure of "-" + Workflow.upsertTypedSearchAttributes( + CUSTOM_CHANGE_VERSION.valueUnset(), + CUSTOM_CHANGE_VERSION.valueSet("add-v2-activity-change-1")); + // Adding call to v2 activity + result += activities.customTwo(input); + } + + // lets say then later on we also want to add a change to invoke another activity + version = Workflow.getVersion("add-v3-activity-change", Workflow.DEFAULT_VERSION, 1); + if (version == 1) { + // Upsert our custom change version search attribute + // We set its value to follow TemporalChangeVersion structure of "-" + Workflow.upsertTypedSearchAttributes( + CUSTOM_CHANGE_VERSION.valueUnset(), + CUSTOM_CHANGE_VERSION.valueSet("add-v3-activity-change-1")); + // Adding call to v2 activity + result += activities.customThree(input); + } + return result; + } +} diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/README.md b/core/src/main/java/io/temporal/samples/customchangeversion/README.md new file mode 100644 index 000000000..0b57250fa --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customchangeversion/README.md @@ -0,0 +1,19 @@ +## Custom Change Version Search Attribute Sample + +This sample shows how to upsert custom search attribute when adding a version change to your workflow code. +It is a current workaround until feature https://github.com/temporalio/sdk-java/issues/587 is implemented. +Purpose of upserting a custom search attribute when addint new versions is to then be able to use +visibility api to search for running/completed executions which are on a specific version. It is also useful to see +if there are no running executions on specific change version in order to remove certain no longer used versioned change +if/else block from your workflow code, so it no longer has to be maintained. + +To run this sample: +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.customchangeversion.CustomChangeVersionStarter +``` + +After running this sample you can go to your Web UI or use Temporal CLI to search for specific CustomChangeVersion, for example: + +``` +temporal workflow list -q "CustomChangeVersion='add-v3-activity-change-1'" +``` \ No newline at end of file From 16ef78b59f0a831851853e11b778aa5233365613 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Wed, 4 Sep 2024 14:49:25 -0400 Subject: [PATCH 193/240] Adding HelloEagerWorkflowStart sample (#670) * adding hello accumulator * updates * Accumulator: adding a test for signal after exit signal, switching out default tests in main * feedback from PR: switching to interface for Deque; removing unnecessary clauses in accumulateGreetings() and processGreeting(); clarifying bad bucket checks * renaming variables and functions based on code review * improvement from code review, setting license to match required license * Accepting Tiho's suggestion to process signals in-loop, reducing use of timers * adding eager workflow start sample * Per Antonio's feedback, adding comments to clarify about eager execution. * formatting changes * improving comments. * comment formatting --- README.md | 1 + .../hello/HelloEagerWorkflowStart.java | 194 ++++++++++++++++++ .../java/io/temporal/samples/hello/README.md | 1 + .../hello/HelloEagerWorkflowStartTest.java | 90 ++++++++ 4 files changed, 286 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloEagerWorkflowStartTest.java diff --git a/README.md b/README.md index 77c00a4e5..1df205ae4 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloChild**](/core/src/main/java/io/temporal/samples/hello/HelloChild.java): Demonstrates how to execute a simple Child Workflow. - [**HelloCron**](/core/src/main/java/io/temporal/samples/hello/HelloCron.java): Demonstrates how to execute a Workflow according to a cron schedule. - [**HelloDynamic**](/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java): Demonstrates how to use `DynamicWorkflow` and `DynamicActivity` interfaces. + - [**HelloEagerWorkflowStart**](/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java): Demonstrates the use of a eager workflow start. - [**HelloPeriodic**](/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java): Demonstrates the use of the Continue-As-New feature. - [**HelloException**](/core/src/main/java/io/temporal/samples/hello/HelloException.java): Demonstrates how to handle exception propagation and wrapping. - [**HelloLocalActivity**](/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java): Demonstrates the use of a [Local Activity](https://docs.temporal.io/docs/jargon/mesh/#local-activity). diff --git a/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java b/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java new file mode 100644 index 000000000..c901753a3 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; +import io.temporal.activity.ActivityOptions; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.time.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Sample Temporal Workflow Definition that starts eagerly and executes a single Local Activity. + * Important elements of eager starting are: the client starting the workflow and the worker + * executing it need to be shared, worker options needs to have .setDisableEagerExecution(false) + * set, the activity is recommended to be a local activity for best performance + */ +public class HelloEagerWorkflowStart { + + // Define the task queue name + static final String TASK_QUEUE = "HelloEagerWorkflowStartTaskQueue"; + + // Define our workflow unique id + static final String WORKFLOW_ID = "HelloEagerWorkflowStartWorkflow"; + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see io.temporal.workflow.WorkflowInterface + * @see io.temporal.workflow.WorkflowMethod + */ + @WorkflowInterface + public interface GreetingWorkflow { + + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + String getGreeting(String name); + } + + /** + * This is the Activity Definition's Interface. Activities are building blocks of any Temporal + * Workflow and contain any business logic that could perform long running computation, network + * calls, etc. + * + *

Annotating Activity Definition methods with @ActivityMethod is optional. + * + * @see io.temporal.activity.ActivityInterface + * @see io.temporal.activity.ActivityMethod + */ + @ActivityInterface + public interface GreetingActivities { + + // Define your activity method which can be called during workflow execution + @ActivityMethod(name = "greet") + String composeGreeting(String greeting, String name); + } + + // Define the workflow implementation which implements our getGreeting workflow method. + public static class GreetingWorkflowImpl implements GreetingWorkflow { + + /** + * Define the GreetingActivities stub. Activity stubs are proxies for activity invocations that + * are executed outside of the workflow thread on the activity worker, that can be on a + * different host. Temporal is going to dispatch the activity results back to the workflow and + * unblock the stub as soon as activity is completed on the activity worker. + * + *

In the {@link ActivityOptions} definition the "setStartToCloseTimeout" option sets the + * overall timeout that our workflow is willing to wait for activity to complete. For this + * example it is set to 2 seconds. + */ + private final GreetingActivities activities = + Workflow.newActivityStub( + GreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String getGreeting(String name) { + // This is a blocking call that returns only after the activity has completed. + return activities.composeGreeting("Hello", name); + } + } + + /** Simple activity implementation, that concatenates two strings. */ + static class GreetingLocalActivitiesImpl implements GreetingActivities { + private static final Logger log = LoggerFactory.getLogger(GreetingLocalActivitiesImpl.class); + + @Override + public String composeGreeting(String greeting, String name) { + log.info("Composing greeting..."); + return greeting + " " + name + "!"; + } + } + + /** + * With our Workflow and Activities defined, we can now start execution. The main method starts + * the worker and then the workflow. + */ + public static void main(String[] args) { + + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + * Here it's important that the worker shares the client for eager execution. + */ + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register our workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); + + /* + * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, + * the Activity Type is a shared instance. + */ + worker.registerActivitiesImplementations(new GreetingLocalActivitiesImpl()); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + // Create the workflow client stub. It is used to start our workflow execution. + GreetingWorkflow workflow = + client.newWorkflowStub( + GreetingWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .setDisableEagerExecution(false) // set this to enable eager execution + .build()); + + /* + * Execute our workflow and wait for it to complete. The call to our getGreeting method is + * synchronous. + * + * See {@link io.temporal.samples.hello.HelloSignal} for an example of starting workflow + * without waiting synchronously for its result. + */ + String greeting = workflow.getGreeting("World"); + + // Display workflow execution results + System.out.println(greeting); + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md index 86eba613b..41dd18271 100644 --- a/core/src/main/java/io/temporal/samples/hello/README.md +++ b/core/src/main/java/io/temporal/samples/hello/README.md @@ -20,6 +20,7 @@ To run each hello world sample, use one of the following commands: ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloChild ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloCron ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloDynamic +./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloEagerWorkflowStart ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloException ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloLocalActivity ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPeriodic diff --git a/core/src/test/java/io/temporal/samples/hello/HelloEagerWorkflowStartTest.java b/core/src/test/java/io/temporal/samples/hello/HelloEagerWorkflowStartTest.java new file mode 100644 index 000000000..563d23824 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloEagerWorkflowStartTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; + +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.hello.HelloEagerWorkflowStart.GreetingActivities; +import io.temporal.samples.hello.HelloEagerWorkflowStart.GreetingLocalActivitiesImpl; +import io.temporal.samples.hello.HelloEagerWorkflowStart.GreetingWorkflow; +import io.temporal.samples.hello.HelloEagerWorkflowStart.GreetingWorkflowImpl; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Rule; +import org.junit.Test; + +/** Unit test for {@link HelloEagerWorkflowStart}. Doesn't use an external Temporal service. */ +public class HelloEagerWorkflowStartTest { + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(GreetingWorkflowImpl.class) + .setDoNotStart(true) + .build(); + + @Test + public void testActivityImpl() { + testWorkflowRule + .getWorker() + .registerActivitiesImplementations(new GreetingLocalActivitiesImpl()); + testWorkflowRule.getTestEnvironment().start(); + + // Get a workflow stub using the same task queue the worker uses. + GreetingWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + GreetingWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + // Execute a workflow waiting for it to complete. + String greeting = workflow.getGreeting("World"); + assertEquals("Hello World!", greeting); + + testWorkflowRule.getTestEnvironment().shutdown(); + } + + @Test + public void testMockedActivity() { + // withoutAnnotations() is required to stop Mockito from copying + // method-level annotations from the GreetingActivities interface + GreetingActivities activities = + mock(GreetingActivities.class, withSettings().withoutAnnotations()); + when(activities.composeGreeting("Hello", "World")).thenReturn("Hello World!"); + testWorkflowRule.getWorker().registerActivitiesImplementations(activities); + testWorkflowRule.getTestEnvironment().start(); + + // Get a workflow stub using the same task queue the worker uses. + GreetingWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + GreetingWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + // Execute a workflow waiting for it to complete. + String greeting = workflow.getGreeting("World"); + assertEquals("Hello World!", greeting); + + testWorkflowRule.getTestEnvironment().shutdown(); + } +} From ec1c615074eaf63d6b09caabff80e374ab507841 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 08:59:43 -0400 Subject: [PATCH 194/240] Bump javaSDKVersion from 1.24.3 to 1.25.0 (#665) Bumps `javaSDKVersion` from 1.24.3 to 1.25.0. Updates `io.temporal:temporal-sdk` from 1.24.3 to 1.25.0 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.24.3...v1.25.0) Updates `io.temporal:temporal-opentracing` from 1.24.3 to 1.25.0 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.24.3...v1.25.0) Updates `io.temporal:temporal-testing` from 1.24.3 to 1.25.0 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.24.3...v1.25.0) Updates `io.temporal:temporal-spring-boot-starter` from 1.24.3 to 1.25.0 - [Release notes](https://github.com/temporalio/sdk-java/releases) - [Commits](https://github.com/temporalio/sdk-java/compare/v1.24.3...v1.25.0) --- updated-dependencies: - dependency-name: io.temporal:temporal-sdk dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.temporal:temporal-opentracing dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.temporal:temporal-testing dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.temporal:temporal-spring-boot-starter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 972142f5b..065224a61 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.24.3' + javaSDKVersion = '1.25.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } From bf1a405d02f2ef231f8585a93b445867cade3c80 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 16 Oct 2024 10:42:17 -0700 Subject: [PATCH 195/240] Add Nexus sample (#686) Add Nexus samples --- build.gradle | 2 +- core/build.gradle | 1 + .../java/io/temporal/samples/nexus/README.MD | 103 +++++++++++++++ .../samples/nexus/caller/CallerStarter.java | 53 ++++++++ .../samples/nexus/caller/CallerWorker.java | 51 +++++++ .../nexus/caller/EchoCallerWorkflow.java | 29 ++++ .../nexus/caller/EchoCallerWorkflowImpl.java | 43 ++++++ .../nexus/caller/HelloCallerWorkflow.java | 30 +++++ .../nexus/caller/HelloCallerWorkflowImpl.java | 50 +++++++ .../samples/nexus/handler/HandlerWorker.java | 41 ++++++ .../nexus/handler/HelloHandlerWorkflow.java | 30 +++++ .../handler/HelloHandlerWorkflowImpl.java | 43 ++++++ .../nexus/handler/NexusServiceImpl.java | 65 +++++++++ .../samples/nexus/options/ClientOptions.java | 125 ++++++++++++++++++ .../samples/nexus/service/NexusService.java | 106 +++++++++++++++ .../samples/nexus/service/description.md | 8 ++ .../nexus/caller/CallerWorkflowTest.java | 109 +++++++++++++++ 17 files changed, 888 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/io/temporal/samples/nexus/README.MD create mode 100644 core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/service/NexusService.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/service/description.md create mode 100644 core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java diff --git a/build.gradle b/build.gradle index 065224a61..e9a3cae26 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.25.0' + javaSDKVersion = '1.26.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/core/build.gradle b/core/build.gradle index c73ce2270..b4653f828 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -28,6 +28,7 @@ dependencies { implementation group: 'io.cloudevents', name: 'cloudevents-api', version: '4.0.1' implementation group: 'io.cloudevents', name: 'cloudevents-json-jackson', version: '3.0.0' implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20240207' + implementation group: 'commons-cli', name: 'commons-cli', version: '1.9.0' // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' diff --git a/core/src/main/java/io/temporal/samples/nexus/README.MD b/core/src/main/java/io/temporal/samples/nexus/README.MD new file mode 100644 index 000000000..2483a8b3f --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/README.MD @@ -0,0 +1,103 @@ +# Nexus + +Temporal Nexus is a new feature of the Temporal platform designed to connect durable executions across team, namespace, +region, and cloud boundaries. It promotes a more modular architecture for sharing a subset of your team’s capabilities +via well-defined service API contracts for other teams to use, that abstract underlying Temporal primitives, like +Workflows, or execute arbitrary code. + +Learn more at [temporal.io/nexus](https://temporal.io/nexus). + +This sample shows how to use Temporal for authoring a Nexus service and call it from a workflow. + +### Sample directory structure + +- [service](./service) - shared service definition +- [caller](./caller) - caller workflows, worker, and starter +- [handler](./handler) - handler workflow, operations, and worker +- [options](./options) - command line argument parsing utility + +## Getting started locally + +### Get `temporal` CLI to enable local development + +1. Follow the instructions on the [docs + site](https://learn.temporal.io/getting_started/go/dev_environment/#set-up-a-local-temporal-service-for-development-with-temporal-cli) + to install Temporal CLI. + +> NOTE: Required version is at least v1.1.0. + +### Spin up environment + +#### Start temporal server + +> HTTP port is required for Nexus communications + +``` +temporal server start-dev --http-port 7243 --dynamic-config-value system.enableNexus=true +``` + +### Initialize environment + +In a separate terminal window + +#### Create caller and target namespaces + +``` +temporal operator namespace create --namespace my-target-namespace +temporal operator namespace create --namespace my-caller-namespace +``` + +#### Create Nexus endpoint + +``` +temporal operator nexus endpoint create \ + --name my-nexus-endpoint-name \ + --target-namespace my-target-namespace \ + --target-task-queue my-handler-task-queue \ + --description-file ./service/description.md +``` + +## Getting started with a self-hosted service or Temporal Cloud + +Nexus is currently available as +[Public Preview](https://docs.temporal.io/evaluate/development-production-features/release-stages). + +Self hosted users can [try Nexus +out](https://github.com/temporalio/temporal/blob/main/docs/architecture/nexus.md#trying-nexus-out) in single cluster +deployments with server version 1.25.0. + +### Make Nexus calls across namespace boundaries + +> Instructions apply for local development, for Temporal Cloud or a self-hosted setups, supply the relevant [CLI +> flags](./options/ClientOptions.java) to properly set up the connection. + +In separate terminal windows: + +### Nexus handler worker + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexus.handler.HandlerWorker \ + --args="-target-host localhost:7233 -namespace my-target-namespace" +``` + +### Nexus caller worker + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexus.caller.CallerWorker \ + --args="-target-host localhost:7233 -namespace my-caller-namespace" +``` + +### Start caller workflow + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexus.caller.CallerStarter \ + --args="-target-host localhost:7233 -namespace my-caller-namespace" +``` + +### Output + +which should result in: +``` +[main] INFO i.t.s.nexus.caller.CallerStarter - Workflow result: Nexus Echo πŸ‘‹ +[main] INFO i.t.s.nexus.caller.CallerStarter - Workflow result: Β‘Hola! Nexus πŸ‘‹ +``` diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java new file mode 100644 index 000000000..23dd0f5ec --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.caller; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.samples.nexus.service.NexusService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CallerStarter { + private static final Logger logger = LoggerFactory.getLogger(CallerStarter.class); + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(CallerWorker.DEFAULT_TASK_QUEUE_NAME).build(); + EchoCallerWorkflow echoWorkflow = + client.newWorkflowStub(EchoCallerWorkflow.class, workflowOptions); + logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); + logger.info( + "Started workflow workflowId: {} runId: {}", + WorkflowStub.fromTyped(echoWorkflow).getExecution().getWorkflowId(), + WorkflowStub.fromTyped(echoWorkflow).getExecution().getRunId()); + HelloCallerWorkflow helloWorkflow = + client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); + logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + logger.info( + "Started workflow workflowId: {} runId: {}", + WorkflowStub.fromTyped(helloWorkflow).getExecution().getWorkflowId(), + WorkflowStub.fromTyped(helloWorkflow).getExecution().getRunId()); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java new file mode 100644 index 000000000..e7be0ae4a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.caller; + +import io.temporal.client.WorkflowClient; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.NexusServiceOptions; +import java.util.Collections; + +public class CallerWorker { + public static final String DEFAULT_TASK_QUEUE_NAME = "my-caller-workflow-task-queue"; + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); + worker.registerWorkflowImplementationTypes( + WorkflowImplementationOptions.newBuilder() + .setNexusServiceOptions( + Collections.singletonMap( + "NexusService", + NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) + .build(), + EchoCallerWorkflowImpl.class, + HelloCallerWorkflowImpl.class); + + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java new file mode 100644 index 000000000..5f830855e --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.caller; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface EchoCallerWorkflow { + @WorkflowMethod + String echo(String message); +} diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java new file mode 100644 index 000000000..7c5d5f787 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.caller; + +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.NexusOperationOptions; +import io.temporal.workflow.NexusServiceOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { + NexusService nexusService = + Workflow.newNexusServiceStub( + NexusService.class, + NexusServiceOptions.newBuilder() + .setOperationOptions( + NexusOperationOptions.newBuilder() + .setScheduleToCloseTimeout(Duration.ofSeconds(10)) + .build()) + .build()); + + @Override + public String echo(String message) { + return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java new file mode 100644 index 000000000..6e943c17e --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.caller; + +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloCallerWorkflow { + @WorkflowMethod + String hello(String message, NexusService.Language language); +} diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java new file mode 100644 index 000000000..dcc8d1a04 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.caller; + +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.NexusOperationHandle; +import io.temporal.workflow.NexusOperationOptions; +import io.temporal.workflow.NexusServiceOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { + NexusService nexusService = + Workflow.newNexusServiceStub( + NexusService.class, + NexusServiceOptions.newBuilder() + .setOperationOptions( + NexusOperationOptions.newBuilder() + .setScheduleToCloseTimeout(Duration.ofSeconds(10)) + .build()) + .build()); + + @Override + public String hello(String message, NexusService.Language language) { + NexusOperationHandle handle = + Workflow.startNexusOperation( + nexusService::hello, new NexusService.HelloInput(message, language)); + // Optionally wait for the operation to be started. NexusOperationExecution will contain the + // operation ID in case this operation is asynchronous. + handle.getExecution().get(); + return handle.getResult().get().getMessage(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java new file mode 100644 index 000000000..71a78f91b --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.handler; + +import io.temporal.client.WorkflowClient; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class HandlerWorker { + public static final String DEFAULT_TASK_QUEUE_NAME = "my-handler-task-queue"; + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); + worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); + worker.registerNexusServiceImplementation(new NexusServiceImpl()); + + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java new file mode 100644 index 000000000..caa34d985 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.handler; + +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloHandlerWorkflow { + @WorkflowMethod + NexusService.HelloOutput hello(NexusService.HelloInput input); +} diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java new file mode 100644 index 000000000..ea5203eb7 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.handler; + +import io.temporal.failure.ApplicationFailure; +import io.temporal.samples.nexus.service.NexusService; + +public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { + @Override + public NexusService.HelloOutput hello(NexusService.HelloInput input) { + switch (input.getLanguage()) { + case EN: + return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + case FR: + return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + case DE: + return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + case ES: + return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + case TR: + return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + } + throw ApplicationFailure.newFailure( + "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java new file mode 100644 index 000000000..4d6cb3cad --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.handler; + +import io.nexusrpc.handler.OperationHandler; +import io.nexusrpc.handler.OperationImpl; +import io.nexusrpc.handler.ServiceImpl; +import io.temporal.client.WorkflowOptions; +import io.temporal.nexus.WorkflowClientOperationHandlers; +import io.temporal.samples.nexus.service.NexusService; + +// To create a service implementation, annotate the class with @ServiceImpl and provide the +// interface that the service implements. The service implementation class should have methods that +// return OperationHandler that correspond to the operations defined in the service interface. +@ServiceImpl(service = NexusService.class) +public class NexusServiceImpl { + @OperationImpl + public OperationHandler echo() { + // WorkflowClientOperationHandlers.sync is a meant for exposing simple RPC handlers. + return WorkflowClientOperationHandlers.sync( + // The method is provided with an SDK client that can be used for arbitrary calls such as + // signaling, querying, + // and listing workflows but implementations are free to make arbitrary calls to other + // services or databases, or + // perform simple computations such as this one. + (ctx, details, client, input) -> new NexusService.EchoOutput(input.getMessage())); + } + + @OperationImpl + public OperationHandler hello() { + // Use the WorkflowClientOperationHandlers.fromWorkflowMethod constructor, which is the easiest + // way to expose a workflow as an operation. + return WorkflowClientOperationHandlers.fromWorkflowMethod( + (ctx, details, client, input) -> + client.newWorkflowStub( + HelloHandlerWorkflow.class, + // Workflow IDs should typically be business meaningful IDs and are used to + // dedupe workflow starts. + // For this example, we're using the request ID allocated by Temporal when the + // caller workflow schedules + // the operation, this ID is guaranteed to be stable across retries of this + // operation. + // + // Task queue defaults to the task queue this operation is handled on. + WorkflowOptions.newBuilder().setWorkflowId(details.getRequestId()).build()) + ::hello); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java new file mode 100644 index 000000000..49d0dde28 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.options; + +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; +import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.Arrays; +import javax.net.ssl.SSLException; +import org.apache.commons.cli.*; + +public class ClientOptions { + public static WorkflowClient getWorkflowClient(String[] args) { + System.out.println(Arrays.toString(args)); + Options options = new Options(); + Option targetHostOption = new Option("target-host", true, "Host:port for the Temporal service"); + targetHostOption.setRequired(false); + options.addOption(targetHostOption); + + Option namespaceOption = new Option("namespace", true, "Namespace to connect to"); + namespaceOption.setRequired(false); + options.addOption(namespaceOption); + + Option serverRootCaOption = + new Option("server-root-ca-cert", true, "Optional path to root server CA cert"); + serverRootCaOption.setRequired(false); + options.addOption(serverRootCaOption); + + Option clientCertOption = new Option("client-cert", true, "Optional path to client cert"); + clientCertOption.setRequired(false); + options.addOption(clientCertOption); + + Option clientKeyOption = new Option("client-key", true, "Optional path to client key"); + clientKeyOption.setRequired(false); + options.addOption(clientKeyOption); + + Option serverNameOption = + new Option( + "server-name", true, "Server name to use for verifying the server's certificate"); + serverNameOption.setRequired(false); + options.addOption(serverNameOption); + + Option insercureSkipVerifyOption = + new Option( + "insecure-skip-verify", + false, + "Skip verification of the server's certificate and host name"); + insercureSkipVerifyOption.setRequired(false); + options.addOption(insercureSkipVerifyOption); + + CommandLineParser parser = new DefaultParser(); + HelpFormatter formatter = new HelpFormatter(); + CommandLine cmd = null; + + try { + cmd = parser.parse(options, args); + } catch (ParseException e) { + System.out.println(e.getMessage()); + formatter.printHelp("utility-name", options); + + System.exit(1); + } + + String targetHost = cmd.getOptionValue("target-host", "localhost:7233"); + String namespace = cmd.getOptionValue("namespace", "default"); + String serverRootCaCert = cmd.getOptionValue("server-root-ca-cert", ""); + String clientCert = cmd.getOptionValue("client-cert", ""); + String clientKey = cmd.getOptionValue("client-key", ""); + String serverName = cmd.getOptionValue("server-name", ""); + boolean insecureSkipVerify = cmd.hasOption("insecure-skip-verify"); + + WorkflowServiceStubsOptions.Builder serviceStubOptionsBuilder = + WorkflowServiceStubsOptions.newBuilder().setTarget(targetHost); + if (!clientCert.isEmpty() || !clientKey.isEmpty()) { + if (clientCert.isEmpty() || clientKey.isEmpty()) { + throw new IllegalArgumentException("Both client-cert and client-key must be provided"); + } + try { + SslContextBuilder sslContext = + SslContextBuilder.forClient() + .keyManager(new FileInputStream(clientCert), new FileInputStream(clientKey)); + if (serverRootCaCert != null && !serverRootCaCert.isEmpty()) { + sslContext.trustManager(new FileInputStream(serverRootCaCert)); + } + if (insecureSkipVerify) { + sslContext.trustManager(InsecureTrustManagerFactory.INSTANCE); + } + serviceStubOptionsBuilder.setSslContext(sslContext.build()); + } catch (SSLException e) { + throw new RuntimeException(e); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + if (serverName != null && !serverName.isEmpty()) { + serviceStubOptionsBuilder.setChannelInitializer(c -> c.overrideAuthority(serverName)); + } + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(serviceStubOptionsBuilder.build()); + return WorkflowClient.newInstance( + service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build()); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java b/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java new file mode 100644 index 000000000..e12dcbe92 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.service; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.nexusrpc.Operation; +import io.nexusrpc.Service; + +@Service +public interface NexusService { + enum Language { + EN, + FR, + DE, + ES, + TR + } + + class HelloInput { + private final String name; + private final Language language; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public HelloInput( + @JsonProperty("name") String name, @JsonProperty("language") Language language) { + this.name = name; + this.language = language; + } + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("language") + public Language getLanguage() { + return language; + } + } + + class HelloOutput { + private final String message; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public HelloOutput(@JsonProperty("message") String message) { + this.message = message; + } + + @JsonProperty("message") + public String getMessage() { + return message; + } + } + + class EchoInput { + private final String message; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public EchoInput(@JsonProperty("message") String message) { + this.message = message; + } + + @JsonProperty("message") + public String getMessage() { + return message; + } + } + + class EchoOutput { + private final String message; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public EchoOutput(@JsonProperty("message") String message) { + this.message = message; + } + + @JsonProperty("message") + public String getMessage() { + return message; + } + } + + @Operation + HelloOutput hello(HelloInput input); + + @Operation + EchoOutput echo(EchoInput input); +} diff --git a/core/src/main/java/io/temporal/samples/nexus/service/description.md b/core/src/main/java/io/temporal/samples/nexus/service/description.md new file mode 100644 index 000000000..74eb4d886 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/service/description.md @@ -0,0 +1,8 @@ +Service Name: +my-hello-service +Operation Names: +echo +say-hello + +Input / Output arguments are in the following repository: +https://github.com/temporalio/samples-java/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java new file mode 100644 index 000000000..ba1bba461 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexus.caller; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; +import io.temporal.samples.nexus.handler.NexusServiceImpl; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.testing.TestWorkflowRule; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.NexusServiceOptions; +import java.util.Collections; +import org.junit.Rule; +import org.junit.Test; + +public class CallerWorkflowTest { + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + // If a Nexus service is registered as part of the test, the TestWorkflowRule will ,by + // default, automatically create a Nexus service endpoint and workflows registered as part + // of the TestWorkflowRule will automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new NexusServiceImpl()) + .setWorkflowTypes(HelloCallerWorkflowImpl.class) + // Disable automatic worker startup as we are going to register some workflows manually + // per test + .setDoNotStart(true) + .build(); + + @Test + public void testHelloWorkflow() { + testWorkflowRule + .getWorker() + // Workflows started by a Nexus service can be mocked just like any other workflow + .registerWorkflowImplementationFactory( + HelloHandlerWorkflow.class, + () -> { + HelloHandlerWorkflow wf = mock(HelloHandlerWorkflow.class); + when(wf.hello(any())).thenReturn(new NexusService.HelloOutput("Hello World πŸ‘‹")); + return wf; + }); + testWorkflowRule.getTestEnvironment().start(); + + HelloCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + String greeting = workflow.hello("World", NexusService.Language.EN); + assertEquals("Hello World πŸ‘‹", greeting); + + testWorkflowRule.getTestEnvironment().shutdown(); + } + + @Test + public void testEchoWorkflow() { + // If Workflows are registered later than the endpoint can be set manually + // either by setting the endpoint in the NexusServiceOptions in the Workflow implementation or + // by setting the NexusServiceOptions on the WorkflowImplementationOptions when registering the + // Workflow. + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes( + WorkflowImplementationOptions.newBuilder() + .setNexusServiceOptions( + Collections.singletonMap( + "NexusService", + NexusServiceOptions.newBuilder() + .setEndpoint(testWorkflowRule.getNexusEndpoint().getSpec().getName()) + .build())) + .build(), + EchoCallerWorkflowImpl.class); + testWorkflowRule.getTestEnvironment().start(); + + EchoCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + EchoCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + String greeting = workflow.echo("Hello"); + assertEquals("Hello", greeting); + testWorkflowRule.getTestEnvironment().shutdown(); + } +} From 72fd4a482765d5199ce834a094f414378fd7ffd8 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Fri, 18 Oct 2024 11:15:59 -0700 Subject: [PATCH 196/240] Fix nexus sample TLS settings (#688) --- core/src/main/java/io/temporal/samples/nexus/README.MD | 2 +- .../io/temporal/samples/nexus/options/ClientOptions.java | 5 ++--- .../java/io/temporal/samples/nexus/service/description.md | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/nexus/README.MD b/core/src/main/java/io/temporal/samples/nexus/README.MD index 2483a8b3f..526d3d486 100644 --- a/core/src/main/java/io/temporal/samples/nexus/README.MD +++ b/core/src/main/java/io/temporal/samples/nexus/README.MD @@ -54,7 +54,7 @@ temporal operator nexus endpoint create \ --name my-nexus-endpoint-name \ --target-namespace my-target-namespace \ --target-task-queue my-handler-task-queue \ - --description-file ./service/description.md + --description-file ./core/src/main/java/io/temporal/samples/nexus/service/description.md ``` ## Getting started with a self-hosted service or Temporal Cloud diff --git a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java index 49d0dde28..95e6d1213 100644 --- a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java +++ b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java @@ -19,6 +19,7 @@ package io.temporal.samples.nexus.options; +import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.temporal.client.WorkflowClient; @@ -27,13 +28,11 @@ import io.temporal.serviceclient.WorkflowServiceStubsOptions; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.util.Arrays; import javax.net.ssl.SSLException; import org.apache.commons.cli.*; public class ClientOptions { public static WorkflowClient getWorkflowClient(String[] args) { - System.out.println(Arrays.toString(args)); Options options = new Options(); Option targetHostOption = new Option("target-host", true, "Host:port for the Temporal service"); targetHostOption.setRequired(false); @@ -107,7 +106,7 @@ public static WorkflowClient getWorkflowClient(String[] args) { if (insecureSkipVerify) { sslContext.trustManager(InsecureTrustManagerFactory.INSTANCE); } - serviceStubOptionsBuilder.setSslContext(sslContext.build()); + serviceStubOptionsBuilder.setSslContext(GrpcSslContexts.configure(sslContext).build()); } catch (SSLException e) { throw new RuntimeException(e); } catch (FileNotFoundException e) { diff --git a/core/src/main/java/io/temporal/samples/nexus/service/description.md b/core/src/main/java/io/temporal/samples/nexus/service/description.md index 74eb4d886..98dc27083 100644 --- a/core/src/main/java/io/temporal/samples/nexus/service/description.md +++ b/core/src/main/java/io/temporal/samples/nexus/service/description.md @@ -1,8 +1,8 @@ Service Name: -my-hello-service +NexusService Operation Names: echo -say-hello +hello Input / Output arguments are in the following repository: https://github.com/temporalio/samples-java/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java From da76e1b36c8d0ff557d323f6ff47f6dc2055b822 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 21 Oct 2024 08:17:10 -0700 Subject: [PATCH 197/240] Add API key option to Nexus sample (#690) Add API key option to Nexus sample --- .../samples/nexus/options/ClientOptions.java | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java index 95e6d1213..7ba699309 100644 --- a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java +++ b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java @@ -19,9 +19,11 @@ package io.temporal.samples.nexus.options; +import io.grpc.Metadata; import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.grpc.stub.MetadataUtils; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.serviceclient.WorkflowServiceStubs; @@ -47,14 +49,23 @@ public static WorkflowClient getWorkflowClient(String[] args) { serverRootCaOption.setRequired(false); options.addOption(serverRootCaOption); - Option clientCertOption = new Option("client-cert", true, "Optional path to client cert"); + Option clientCertOption = + new Option( + "client-cert", true, "Optional path to client cert, mutually exclusive with API key"); clientCertOption.setRequired(false); options.addOption(clientCertOption); - Option clientKeyOption = new Option("client-key", true, "Optional path to client key"); + Option clientKeyOption = + new Option( + "client-key", true, "Optional path to client key, mutually exclusive with API key"); clientKeyOption.setRequired(false); options.addOption(clientKeyOption); + Option apiKeyOption = + new Option("api-key", true, "Optional API key, mutually exclusive with cert/key"); + apiKeyOption.setRequired(false); + options.addOption(apiKeyOption); + Option serverNameOption = new Option( "server-name", true, "Server name to use for verifying the server's certificate"); @@ -89,9 +100,15 @@ public static WorkflowClient getWorkflowClient(String[] args) { String clientKey = cmd.getOptionValue("client-key", ""); String serverName = cmd.getOptionValue("server-name", ""); boolean insecureSkipVerify = cmd.hasOption("insecure-skip-verify"); + String apiKey = cmd.getOptionValue("api-key", ""); + // API key and client cert/key are mutually exclusive + if (!apiKey.isEmpty() && (!clientCert.isEmpty() || !clientKey.isEmpty())) { + throw new IllegalArgumentException("API key and client cert/key are mutually exclusive"); + } WorkflowServiceStubsOptions.Builder serviceStubOptionsBuilder = WorkflowServiceStubsOptions.newBuilder().setTarget(targetHost); + // Configure TLS if client cert and key are provided if (!clientCert.isEmpty() || !clientKey.isEmpty()) { if (clientCert.isEmpty() || clientKey.isEmpty()) { throw new IllegalArgumentException("Both client-cert and client-key must be provided"); @@ -112,10 +129,24 @@ public static WorkflowClient getWorkflowClient(String[] args) { } catch (FileNotFoundException e) { throw new RuntimeException(e); } + if (serverName != null && !serverName.isEmpty()) { + serviceStubOptionsBuilder.setChannelInitializer(c -> c.overrideAuthority(serverName)); + } } - if (serverName != null && !serverName.isEmpty()) { - serviceStubOptionsBuilder.setChannelInitializer(c -> c.overrideAuthority(serverName)); + // Configure API key if provided + if (!apiKey.isEmpty()) { + serviceStubOptionsBuilder.setEnableHttps(true); + serviceStubOptionsBuilder.addApiKey(() -> apiKey); + Metadata.Key TEMPORAL_NAMESPACE_HEADER_KEY = + Metadata.Key.of("temporal-namespace", Metadata.ASCII_STRING_MARSHALLER); + Metadata metadata = new Metadata(); + metadata.put(TEMPORAL_NAMESPACE_HEADER_KEY, namespace); + serviceStubOptionsBuilder.setChannelInitializer( + (channel) -> { + channel.intercept(MetadataUtils.newAttachHeadersInterceptor(metadata)); + }); } + WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(serviceStubOptionsBuilder.build()); return WorkflowClient.newInstance( From 71e251dd642378f7ec69785dcbb8c6352fe3f636 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Thu, 24 Oct 2024 15:26:01 -0700 Subject: [PATCH 198/240] Bump Java SDK to v1.26.1 (#695) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e9a3cae26..cdd85c168 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.26.0' + javaSDKVersion = '1.26.1' camelVersion = '3.22.1' jarVersion = '1.0.0' } From 58124a87853f12559886f7dcf2cccfec4368a201 Mon Sep 17 00:00:00 2001 From: Steve Androulakis Date: Tue, 29 Oct 2024 11:33:00 -0700 Subject: [PATCH 199/240] EarlyReturn sample (Update-With-Start) (#689) EarlyReturn sample (Update-With-Start) --------- Co-authored-by: Stephan Behnke Co-authored-by: Quinn Klassen --- .../earlyreturn/EarlyReturnClient.java | 90 ++++++++++ .../earlyreturn/EarlyReturnWorker.java | 44 +++++ .../io/temporal/samples/earlyreturn/README.md | 24 +++ .../samples/earlyreturn/Transaction.java | 69 ++++++++ .../earlyreturn/TransactionActivities.java | 38 +++++ .../TransactionActivitiesImpl.java | 78 +++++++++ .../earlyreturn/TransactionRequest.java | 61 +++++++ .../earlyreturn/TransactionWorkflow.java | 33 ++++ .../earlyreturn/TransactionWorkflowImpl.java | 72 ++++++++ .../samples/earlyreturn/TxResult.java | 51 ++++++ .../earlyreturn/TransactionWorkflowTest.java | 157 ++++++++++++++++++ 11 files changed, 717 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/README.md create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/Transaction.java create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java create mode 100644 core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java new file mode 100644 index 000000000..6ccb11da1 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import io.temporal.client.*; +import io.temporal.serviceclient.WorkflowServiceStubs; + +public class EarlyReturnClient { + private static final String TASK_QUEUE = "EarlyReturnTaskQueue"; + private static final String WORKFLOW_ID_PREFIX = "early-return-workflow-"; + + public static void main(String[] args) { + WorkflowClient client = setupWorkflowClient(); + runWorkflowWithUpdateWithStart(client); + } + + // Set up the WorkflowClient + public static WorkflowClient setupWorkflowClient() { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + return WorkflowClient.newInstance(service); + } + + // Run workflow using 'updateWithStart' + private static void runWorkflowWithUpdateWithStart(WorkflowClient client) { + TransactionRequest txRequest = + new TransactionRequest( + "Bob", "Alice", + 1000); // Change this amount to a negative number to have initTransaction fail + + WorkflowOptions options = buildWorkflowOptions(); + TransactionWorkflow workflow = client.newWorkflowStub(TransactionWorkflow.class, options); + + System.out.println("Starting workflow with UpdateWithStart"); + + UpdateWithStartWorkflowOperation updateOp = + UpdateWithStartWorkflowOperation.newBuilder(workflow::returnInitResult) + .setWaitForStage(WorkflowUpdateStage.COMPLETED) // Wait for update to complete + .build(); + + TxResult updateResult = null; + try { + WorkflowUpdateHandle updateHandle = + WorkflowClient.updateWithStart(workflow::processTransaction, txRequest, updateOp); + + updateResult = updateHandle.getResultAsync().get(); + + System.out.println( + "Workflow initialized with result: " + + updateResult.getStatus() + + " (transactionId: " + + updateResult.getTransactionId() + + ")"); + + TxResult result = WorkflowStub.fromTyped(workflow).getResult(TxResult.class); + System.out.println( + "Workflow completed with result: " + + result.getStatus() + + " (transactionId: " + + result.getTransactionId() + + ")"); + } catch (Exception e) { + System.err.println("Transaction initialization failed: " + e.getMessage()); + } + } + + // Build WorkflowOptions with task queue and unique ID + private static WorkflowOptions buildWorkflowOptions() { + return WorkflowOptions.newBuilder() + .setTaskQueue(TASK_QUEUE) + .setWorkflowId(WORKFLOW_ID_PREFIX + System.currentTimeMillis()) + .build(); + } +} diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java new file mode 100644 index 000000000..222368ec6 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import io.temporal.client.WorkflowClient; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class EarlyReturnWorker { + private static final String TASK_QUEUE = "EarlyReturnTaskQueue"; + + public static void main(String[] args) { + WorkflowClient client = EarlyReturnClient.setupWorkflowClient(); + startWorker(client); + } + + private static void startWorker(WorkflowClient client) { + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(TASK_QUEUE); + + worker.registerWorkflowImplementationTypes(TransactionWorkflowImpl.class); + worker.registerActivitiesImplementations(new TransactionActivitiesImpl()); + + factory.start(); + System.out.println("Worker started"); + } +} diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/README.md b/core/src/main/java/io/temporal/samples/earlyreturn/README.md new file mode 100644 index 000000000..f0c486608 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/README.md @@ -0,0 +1,24 @@ +### Early-Return Sample + +This sample demonstrates an early-return from a workflow. + +By utilizing Update-with-Start, a client can start a new workflow and synchronously receive +a response mid-workflow, while the workflow continues to run to completion. + +To run the sample, start the worker: +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.earlyreturn.EarlyReturnWorker +``` + +Then, start the client: + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.earlyreturn.EarlyReturnClient +``` + +* The client will start a workflow using Update-With-Start. +* Update-With-Start will trigger an initialization step. +* If the initialization step succeeds (default), intialization will return to the client with a transaction ID and the workflow will continue. The workflow will then complete and return the final result. +* If the intitialization step fails (amount <= 0), the workflow will return to the client with an error message and the workflow will run an activity to cancel the transaction. + +To trigger a failed initialization, set the amount to <= 0 in the `EarlyReturnClient` class's `runWorkflowWithUpdateWithStart` method and re-run the client. \ No newline at end of file diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/Transaction.java b/core/src/main/java/io/temporal/samples/earlyreturn/Transaction.java new file mode 100644 index 000000000..0f910b4fd --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/Transaction.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public final class Transaction { + private final String id; + private final String sourceAccount; + private final String targetAccount; + private final int amount; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public Transaction( + @JsonProperty("id") String id, + @JsonProperty("sourceAccount") String sourceAccount, + @JsonProperty("targetAccount") String targetAccount, + @JsonProperty("amount") int amount) { + this.id = id; + this.sourceAccount = sourceAccount; + this.targetAccount = targetAccount; + this.amount = amount; + } + + @JsonProperty("id") + public String getId() { + return id; + } + + @JsonProperty("sourceAccount") + public String getSourceAccount() { + return sourceAccount; + } + + @JsonProperty("targetAccount") + public String getTargetAccount() { + return targetAccount; + } + + @JsonProperty("amount") + public int getAmount() { + return amount; + } + + @Override + public String toString() { + return String.format( + "Transaction{id='%s', sourceAccount='%s', targetAccount='%s', amount=%d}", + id, sourceAccount, targetAccount, amount); + } +} diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java new file mode 100644 index 000000000..8f3e866f8 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; + +@ActivityInterface +public interface TransactionActivities { + @ActivityMethod + Transaction mintTransactionId(TransactionRequest txRequest); + + @ActivityMethod + Transaction initTransaction(Transaction tx); + + @ActivityMethod + void cancelTransaction(Transaction tx); + + @ActivityMethod + void completeTransaction(Transaction tx); +} diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivitiesImpl.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivitiesImpl.java new file mode 100644 index 000000000..52dc61806 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivitiesImpl.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import io.temporal.failure.ApplicationFailure; + +public class TransactionActivitiesImpl implements TransactionActivities { + + @Override + public Transaction mintTransactionId(TransactionRequest request) { + System.out.println("Minting transaction ID"); + // Simulate transaction ID generation + String txId = "TXID" + String.format("%010d", (long) (Math.random() * 1_000_000_0000L)); + sleep(100); + System.out.println("Transaction ID minted: " + txId); + return new Transaction( + txId, request.getSourceAccount(), request.getTargetAccount(), request.getAmount()); + } + + @Override + public Transaction initTransaction(Transaction tx) { + System.out.println("Initializing transaction"); + sleep(300); + if (tx.getAmount() <= 0) { + System.out.println("Invalid amount: " + tx.getAmount()); + throw ApplicationFailure.newNonRetryableFailure( + "Non-retryable Activity Failure: Invalid Amount", "InvalidAmount"); + } + + sleep(500); + return tx; + } + + @Override + public void cancelTransaction(Transaction tx) { + System.out.println("Cancelling transaction"); + sleep(300); + System.out.println("Transaction cancelled"); + } + + @Override + public void completeTransaction(Transaction tx) { + System.out.println( + "Sending $" + + tx.getAmount() + + " from " + + tx.getSourceAccount() + + " to " + + tx.getTargetAccount()); + sleep(2000); + System.out.println("Transaction completed successfully"); + } + + private void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java new file mode 100644 index 000000000..c174a63f8 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public final class TransactionRequest { + private final String sourceAccount; + private final String targetAccount; + private final int amount; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public TransactionRequest( + @JsonProperty("sourceAccount") String sourceAccount, + @JsonProperty("targetAccount") String targetAccount, + @JsonProperty("amount") int amount) { + this.sourceAccount = sourceAccount; + this.targetAccount = targetAccount; + this.amount = amount; + } + + @JsonProperty("sourceAccount") + public String getSourceAccount() { + return sourceAccount; + } + + @JsonProperty("targetAccount") + public String getTargetAccount() { + return targetAccount; + } + + @JsonProperty("amount") + public int getAmount() { + return amount; + } + + @Override + public String toString() { + return String.format( + "TransactionRequest{sourceAccount='%s', targetAccount='%s', amount=%d}", + sourceAccount, targetAccount, amount); + } +} diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java new file mode 100644 index 000000000..2d1ef6f5f --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import io.temporal.workflow.UpdateMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface TransactionWorkflow { + @WorkflowMethod + TxResult processTransaction(TransactionRequest txRequest); + + @UpdateMethod(name = "early-return") + TxResult returnInitResult(); +} diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflowImpl.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflowImpl.java new file mode 100644 index 000000000..8f7c86d34 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflowImpl.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionWorkflowImpl implements TransactionWorkflow { + private static final Logger log = LoggerFactory.getLogger(TransactionWorkflowImpl.class); + private final TransactionActivities activities = + Workflow.newActivityStub( + TransactionActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(30)).build()); + + private boolean initDone = false; + private Transaction tx; + private Exception initError = null; + + @Override + public TxResult processTransaction(TransactionRequest txRequest) { + this.tx = activities.mintTransactionId(txRequest); + + try { + this.tx = activities.initTransaction(this.tx); + } catch (Exception e) { + initError = e; + } finally { + initDone = true; + } + + if (initError != null) { + // If initialization failed, cancel the transaction + activities.cancelTransaction(this.tx); + return new TxResult("", "Transaction cancelled."); + } else { + activities.completeTransaction(this.tx); + return new TxResult(this.tx.getId(), "Transaction completed successfully."); + } + } + + @Override + public TxResult returnInitResult() { + Workflow.await(() -> initDone); + + if (initError != null) { + log.info("Initialization failed."); + throw Workflow.wrap(initError); + } + + return new TxResult(tx.getId(), "Initialization successful"); + } +} diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java b/core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java new file mode 100644 index 000000000..04c9a9862 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class TxResult { + private final String transactionId; + private final String status; + + // Jackson-compatible constructor with @JsonCreator and @JsonProperty annotations + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public TxResult( + @JsonProperty("transactionId") String transactionId, @JsonProperty("status") String status) { + this.transactionId = transactionId; + this.status = status; + } + + @JsonProperty("transactionId") + public String getTransactionId() { + return transactionId; + } + + @JsonProperty("status") + public String getStatus() { + return status; + } + + @Override + public String toString() { + return String.format("InitResult{transactionId='%s', status='%s'}", transactionId, status); + } +} diff --git a/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java b/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java new file mode 100644 index 000000000..5661d28a9 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.earlyreturn; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import io.temporal.client.*; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.ApplicationFailure; +import io.temporal.testing.TestWorkflowRule; +import java.util.UUID; +import org.junit.Rule; +import org.junit.Test; + +public class TransactionWorkflowTest { + + private static final String SOURCE_ACCOUNT = "Bob"; + private static final String TARGET_ACCOUNT = "Alice"; + private static final String TEST_TRANSACTION_ID = "test-id-123"; + private static final int VALID_AMOUNT = 1000; + private static final int INVALID_AMOUNT = -1000; + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(TransactionWorkflowImpl.class) + .setDoNotStart(true) + .build(); + + @Test + public void testUpdateWithStartValidAmount() throws Exception { + // Mock activities + TransactionActivities activities = + mock(TransactionActivities.class, withSettings().withoutAnnotations()); + when(activities.initTransaction(any())) + .thenReturn( + new Transaction(TEST_TRANSACTION_ID, SOURCE_ACCOUNT, TARGET_ACCOUNT, VALID_AMOUNT)); + + testWorkflowRule.getWorker().registerActivitiesImplementations(activities); + testWorkflowRule.getTestEnvironment().start(); + + // Create workflow stub + WorkflowClient workflowClient = testWorkflowRule.getWorkflowClient(); + TransactionWorkflow workflow = + workflowClient.newWorkflowStub( + TransactionWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + // Create update operation + UpdateWithStartWorkflowOperation updateOp = + UpdateWithStartWorkflowOperation.newBuilder(workflow::returnInitResult) + .setWaitForStage(WorkflowUpdateStage.COMPLETED) + .build(); + + // Execute UpdateWithStart + WorkflowUpdateHandle handle = + WorkflowClient.updateWithStart( + workflow::processTransaction, + new TransactionRequest(SOURCE_ACCOUNT, TARGET_ACCOUNT, VALID_AMOUNT), + updateOp); + + // Verify both update and final results + TxResult updateResult = handle.getResultAsync().get(); + assertEquals(TEST_TRANSACTION_ID, updateResult.getTransactionId()); + + TxResult finalResult = WorkflowStub.fromTyped(workflow).getResult(TxResult.class); + assertEquals("Transaction completed successfully.", finalResult.getStatus()); + + // Verify activities were calledgit + verify(activities).mintTransactionId(any()); + verify(activities).initTransaction(any()); + verify(activities).completeTransaction(any()); + verifyNoMoreInteractions(activities); + } + + @Test + public void testUpdateWithStartInvalidAmount() throws Exception { + // Mock activities + TransactionActivities activities = + mock(TransactionActivities.class, withSettings().withoutAnnotations()); + when(activities.initTransaction(any())) + .thenThrow( + ApplicationFailure.newNonRetryableFailure( + "Non-retryable Activity Failure: Invalid Amount", "InvalidAmount")); + doNothing().when(activities).cancelTransaction(any()); + + testWorkflowRule.getWorker().registerActivitiesImplementations(activities); + testWorkflowRule.getTestEnvironment().start(); + + // Create workflow stub with explicit ID + WorkflowClient workflowClient = testWorkflowRule.getWorkflowClient(); + String workflowId = "test-workflow-" + UUID.randomUUID(); + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowId(workflowId) + .build(); + + TransactionWorkflow workflow = + workflowClient.newWorkflowStub(TransactionWorkflow.class, options); + + // Create update operation + UpdateWithStartWorkflowOperation updateOp = + UpdateWithStartWorkflowOperation.newBuilder(workflow::returnInitResult) + .setWaitForStage(WorkflowUpdateStage.COMPLETED) + .build(); + + // Execute UpdateWithStart and expect the exception + WorkflowServiceException exception = + assertThrows( + WorkflowServiceException.class, + () -> + WorkflowClient.updateWithStart( + workflow::processTransaction, + new TransactionRequest(SOURCE_ACCOUNT, TARGET_ACCOUNT, INVALID_AMOUNT), + updateOp)); + + // Verify the exception chain + assertTrue(exception.getCause() instanceof WorkflowUpdateException); + assertTrue(exception.getCause().getCause() instanceof ActivityFailure); + ApplicationFailure appFailure = (ApplicationFailure) exception.getCause().getCause().getCause(); + assertEquals("InvalidAmount", appFailure.getType()); + assertTrue(appFailure.getMessage().contains("Invalid Amount")); + + // Create a new stub to get the result + TransactionWorkflow workflowById = + workflowClient.newWorkflowStub(TransactionWorkflow.class, workflowId); + TxResult finalResult = WorkflowStub.fromTyped(workflowById).getResult(TxResult.class); + assertEquals("", finalResult.getTransactionId()); + assertEquals("Transaction cancelled.", finalResult.getStatus()); + + // Verify activities were called in correct order + verify(activities).mintTransactionId(any()); + verify(activities).initTransaction(any()); + verify(activities).cancelTransaction(any()); + verifyNoMoreInteractions(activities); + } +} From 0da77167c27f9f95e0f6a3014fa09219a8d161f5 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 29 Oct 2024 11:33:17 -0700 Subject: [PATCH 200/240] Upgrade gradle (#697) --- build.gradle | 2 +- .../DynamicSleepWorkflowWorker.java | 1 + .../IteratorIteratorBatchWorkflowTest.java | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 61608 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 34 +++++++++++------- gradlew.bat | 22 ++++++------ 7 files changed, 38 insertions(+), 25 deletions(-) diff --git a/build.gradle b/build.gradle index cdd85c168..43c50ce5b 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ subprojects { java { target 'src/*/java/**/*.java' targetExclude '**/.idea/**' - googleJavaFormat('1.16.0') + googleJavaFormat('1.24.0') } } diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java index fe797c4db..14429ea0e 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java @@ -31,6 +31,7 @@ public class DynamicSleepWorkflowWorker { static final String TASK_QUEUE = "TimerUpdate"; private static final Logger logger = LoggerFactory.getLogger(DynamicSleepWorkflowWorker.class); + /** Create just one workflow instance for the sake of the sample. */ static final String DYNAMIC_SLEEP_WORKFLOW_ID = "DynamicSleepWorkflow"; diff --git a/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java b/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java index edc6ec250..91cae65b7 100644 --- a/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java @@ -30,6 +30,7 @@ public class IteratorIteratorBatchWorkflowTest { private static final int PAGE_SIZE = 10; + /** The sample RecordLoaderImpl always returns the fixed number pages. */ private static boolean[] processedRecords = new boolean[PAGE_SIZE * PAGE_COUNT]; diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ccebba7710deaf9f98673a68957ea02138b60d0a..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 61608 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fc10b601f..df97d72b8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 79a61d421..f5feea6d6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,10 +85,9 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +134,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +201,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 6689b85be..9b42019c7 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail From 5c96864e2c6e45963bee2f9b13605d24670f8b1a Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 29 Oct 2024 18:56:45 -0700 Subject: [PATCH 201/240] safe message passing sample (#681) Add safe message passing sample --- README.md | 2 + .../ClusterManagerActivities.java | 102 ++++++++ .../ClusterManagerActivitiesImpl.java | 82 ++++++ .../ClusterManagerWorkflow.java | 171 ++++++++++++ .../ClusterManagerWorkflowImpl.java | 244 ++++++++++++++++++ .../ClusterManagerWorkflowStarter.java | 114 ++++++++ .../ClusterManagerWorkflowWorker.java | 44 ++++ .../samples/safemessagepassing/README.md | 22 ++ .../ClusterManagerWorkflowWorkerTest.java | 157 +++++++++++ 9 files changed, 938 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivities.java create mode 100644 core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java create mode 100644 core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java create mode 100644 core/src/main/java/io/temporal/samples/safemessagepassing/README.md create mode 100644 core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java diff --git a/README.md b/README.md index 1df205ae4..ebc558209 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Sliding Window Batch**](/core/src/main/java/io/temporal/samples/batch/slidingwindow): A batch implementation that maintains a configured number of child workflows during processing. +- [**Safe Message Passing**](/core/src/main/java/io/temporal/samples/safemessagepassing): Safely handling concurrent updates and signals messages. + #### API demonstrations - [**Async Untyped Child Workflow**](/core/src/main/java/io/temporal/samples/asyncuntypedchild): Demonstrates how to invoke an untyped child workflow async, that can complete after parent workflow is already completed. diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivities.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivities.java new file mode 100644 index 000000000..267a9626f --- /dev/null +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivities.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.safemessagepassing; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; +import java.util.List; +import java.util.Set; + +@ActivityInterface +public interface ClusterManagerActivities { + + class AssignNodesToJobInput { + private final List nodes; + private final String jobName; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public AssignNodesToJobInput( + @JsonProperty("nodes_to_assign") Set nodesToAssign, + @JsonProperty("job_name") String jobName) { + this.nodes = List.copyOf(nodesToAssign); + this.jobName = jobName; + } + + @JsonProperty("nodes_to_assign") + public List getNodes() { + return nodes; + } + + @JsonProperty("job_name") + public String getJobName() { + return jobName; + } + } + + @ActivityMethod + void assignNodesToJob(AssignNodesToJobInput input); + + class UnassignNodesForJobInput { + private final List nodes; + private final String jobName; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public UnassignNodesForJobInput( + @JsonProperty("nodes") Set nodes, @JsonProperty("job_name") String jobName) { + this.nodes = List.copyOf(nodes); + this.jobName = jobName; + } + + @JsonProperty("nodes") + public List getNodes() { + return nodes; + } + + @JsonProperty("job_name") + public String getJobName() { + return jobName; + } + } + + @ActivityMethod + void unassignNodesForJob(UnassignNodesForJobInput input); + + class FindBadNodesInput { + private final Set nodesToCheck; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public FindBadNodesInput(@JsonProperty("assigned_nodes") Set assignedNodes) { + this.nodesToCheck = assignedNodes; + } + + @JsonProperty("assigned_nodes") + public Set getNodesToCheck() { + return nodesToCheck; + } + } + + @ActivityMethod + Set findBadNodes(FindBadNodesInput input); + + @ActivityMethod + void shutdown(); +} diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivitiesImpl.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivitiesImpl.java new file mode 100644 index 000000000..827ea2e1b --- /dev/null +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivitiesImpl.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.safemessagepassing; + +import java.util.Set; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClusterManagerActivitiesImpl implements ClusterManagerActivities { + private static final Logger log = LoggerFactory.getLogger(ClusterManagerActivitiesImpl.class); + + @Override + public void assignNodesToJob(AssignNodesToJobInput input) { + for (String node : input.getNodes()) { + log.info("Assigned node " + node + " to job " + input.getJobName()); + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Override + public void unassignNodesForJob(UnassignNodesForJobInput input) { + for (String node : input.getNodes()) { + log.info("Unassigned node " + node + " from job " + input.getJobName()); + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Override + public Set findBadNodes(FindBadNodesInput input) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + Set badNodes = + input.getNodesToCheck().stream() + .filter(n -> Integer.parseInt(n) % 5 == 0) + .collect(Collectors.toSet()); + if (!badNodes.isEmpty()) { + log.info("Found bad nodes: " + badNodes); + } else { + log.info("No bad nodes found"); + } + return badNodes; + } + + @Override + public void shutdown() { + log.info("Shutting down cluster"); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java new file mode 100644 index 000000000..52ab24476 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.safemessagepassing; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.UpdateMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.util.*; + +/** + * ClusterManagerWorkflow keeps track of the assignments of a cluster of nodes. Via signals, the + * cluster can be started and shutdown. Via updates, clients can also assign jobs to nodes and + * delete jobs. These updates must run atomically. + */ +@WorkflowInterface +public interface ClusterManagerWorkflow { + + enum ClusterState { + NOT_STARTED, + STARTED, + SHUTTING_DOWN + } + // In workflows that continue-as-new, it's convenient to store all your state in one serializable + // structure to make it easier to pass between runs + class ClusterManagerState { + public ClusterState workflowState = ClusterState.NOT_STARTED; + public Map> nodes = new HashMap<>(); + public Set jobAssigned = new HashSet<>(); + } + + class ClusterManagerInput { + private final Optional state; + private final boolean testContinueAsNew; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public ClusterManagerInput( + @JsonProperty("state") Optional state, + @JsonProperty("test_continue_as_new") boolean testContinueAsNew) { + this.state = state; + this.testContinueAsNew = testContinueAsNew; + } + + @JsonProperty("state") + public Optional getState() { + return state; + } + + @JsonProperty("test_continue_as_new") + public boolean isTestContinueAsNew() { + return testContinueAsNew; + } + } + + class ClusterManagerResult { + private final int numCurrentlyAssignedNodes; + private final int numBadNodes; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public ClusterManagerResult( + @JsonProperty("num_currently_assigned_nodes") int numCurrentlyAssignedNodes, + @JsonProperty("num_bad_nodes") int numBadNodes) { + this.numCurrentlyAssignedNodes = numCurrentlyAssignedNodes; + this.numBadNodes = numBadNodes; + } + + @JsonProperty("num_currently_assigned_nodes") + public int getNumCurrentlyAssignedNodes() { + return numCurrentlyAssignedNodes; + } + + @JsonProperty("num_bad_nodes") + public int getNumBadNodes() { + return numBadNodes; + } + } + + // Be in the habit of storing message inputs and outputs in serializable structures. + // This makes it easier to add more overtime in a backward-compatible way. + class ClusterManagerAssignNodesToJobInput { + // If larger or smaller than previous amounts, will resize the job. + private final int totalNumNodes; + private final String jobName; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public ClusterManagerAssignNodesToJobInput( + @JsonProperty("total_num_nodes") int totalNumNodes, + @JsonProperty("job_name") String jobName) { + this.totalNumNodes = totalNumNodes; + this.jobName = jobName; + } + + @JsonProperty("total_num_nodes") + public int getTotalNumNodes() { + return totalNumNodes; + } + + @JsonProperty("job_name") + public String getJobName() { + return jobName; + } + } + + class ClusterManagerDeleteJobInput { + private final String jobName; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public ClusterManagerDeleteJobInput(@JsonProperty("job_name") String jobName) { + this.jobName = jobName; + } + + @JsonProperty("job_name") + public String getJobName() { + return jobName; + } + } + + class ClusterManagerAssignNodesToJobResult { + private final Set nodesAssigned; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public ClusterManagerAssignNodesToJobResult( + @JsonProperty("assigned_nodes") Set assignedNodes) { + this.nodesAssigned = assignedNodes; + } + + @JsonProperty("assigned_nodes") + public Set getNodesAssigned() { + return nodesAssigned; + } + } + + @WorkflowMethod + ClusterManagerResult run(ClusterManagerInput input); + + @SignalMethod + void startCluster(); + + @UpdateMethod + boolean stopCluster(); + + // This is an update as opposed to a signal because the client may want to wait for nodes to be + // allocated before sending work to those nodes. Returns the list of node names that were + // allocated to the job. + @UpdateMethod + ClusterManagerAssignNodesToJobResult assignNodesToJobs(ClusterManagerAssignNodesToJobInput input); + + // Even though it returns nothing, this is an update because the client may want to track it, for + // example to wait for nodes to be unassigned before reassigning them. + @UpdateMethod + void deleteJob(ClusterManagerDeleteJobInput input); +} diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowImpl.java new file mode 100644 index 000000000..d25453eca --- /dev/null +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowImpl.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.safemessagepassing; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.RetryOptions; +import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInit; +import io.temporal.workflow.WorkflowLock; +import java.time.Duration; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClusterManagerWorkflowImpl implements ClusterManagerWorkflow { + + private static final Logger logger = LoggerFactory.getLogger(ClusterManagerWorkflowImpl.class); + private final ClusterManagerState state; + private final WorkflowLock nodeLock; + private final Duration sleepInterval; + private final int maxHistoryLength; + + private ClusterManagerActivities activities = + Workflow.newActivityStub( + ClusterManagerActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build(), + Collections.singletonMap( + "findBadNodes", + ActivityOptions.newBuilder() + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) + .build())); + + @WorkflowInit + public ClusterManagerWorkflowImpl(ClusterManagerInput input) { + nodeLock = Workflow.newWorkflowLock(); + if (input.getState().isPresent()) { + state = input.getState().get(); + } else { + state = new ClusterManagerState(); + } + if (input.isTestContinueAsNew()) { + maxHistoryLength = 120; + sleepInterval = Duration.ofSeconds(1); + } else { + sleepInterval = Duration.ofSeconds(10); + maxHistoryLength = 0; + } + } + + @Override + public ClusterManagerResult run(ClusterManagerInput input) { + Workflow.await(() -> state.workflowState != ClusterState.NOT_STARTED); + // The cluster manager is a long-running "entity" workflow so we need to periodically checkpoint + // its state and + // continue-as-new. + while (true) { + performHealthChecks(); + if (!Workflow.await( + sleepInterval, + () -> state.workflowState == ClusterState.SHUTTING_DOWN || shouldContinueAsNew())) { + } else if (state.workflowState == ClusterState.SHUTTING_DOWN) { + break; + } else if (shouldContinueAsNew()) { + // We don't want to leave any job assignment or deletion handlers half-finished when we + // continue as new. + Workflow.await(() -> Workflow.isEveryHandlerFinished()); + logger.info("Continuing as new"); + Workflow.continueAsNew( + new ClusterManagerInput(Optional.of(state), input.isTestContinueAsNew())); + } + } + // Make sure we finish off handlers such as deleting jobs before we complete the workflow. + Workflow.await(() -> Workflow.isEveryHandlerFinished()); + return new ClusterManagerResult(getAssignedNodes(null).size(), getBadNodes().size()); + } + + @Override + public void startCluster() { + if (state.workflowState != ClusterState.NOT_STARTED) { + logger.warn("Cannot start cluster in state {}", state.workflowState); + return; + } + state.workflowState = ClusterState.STARTED; + for (int i = 0; i < 25; i++) { + state.nodes.put(String.valueOf(i), Optional.empty()); + } + logger.info("Cluster started"); + } + + @Override + public boolean stopCluster() { + if (state.workflowState != ClusterState.STARTED) { + // This is used as an Update handler so that we can return an error to the caller. + throw ApplicationFailure.newFailure( + "Cannot shutdown cluster in state " + state.workflowState, "IllegalState"); + } + activities.shutdown(); + state.workflowState = ClusterState.SHUTTING_DOWN; + logger.info("Cluster shut down"); + return true; + } + + @Override + public ClusterManagerAssignNodesToJobResult assignNodesToJobs( + ClusterManagerAssignNodesToJobInput input) { + Workflow.await(() -> state.workflowState != ClusterState.NOT_STARTED); + if (state.workflowState == ClusterState.SHUTTING_DOWN) { + throw ApplicationFailure.newFailure( + "Cannot assign nodes to a job: Cluster is already shut down", "IllegalState"); + } + nodeLock.lock(); + try { + // Idempotency guard. + if (state.jobAssigned.contains(input.getJobName())) { + return new ClusterManagerAssignNodesToJobResult(getAssignedNodes(input.getJobName())); + } + Set unassignedNodes = getUnassignedNodes(); + if (unassignedNodes.size() < input.getTotalNumNodes()) { + // If you want the client to receive a failure, either add an update validator and throw the + // exception from there, or raise an ApplicationFailure. Other exceptions in the main + // handler will cause the workflow to keep retrying and get it stuck. + throw ApplicationFailure.newFailure( + "Cannot assign nodes to a job: Not enough nodes available", "IllegalState"); + } + Set nodesToAssign = + unassignedNodes.stream().limit(input.getTotalNumNodes()).collect(Collectors.toSet()); + // This call would be dangerous without nodesLock because it yields control and allows + // interleaving with deleteJob and performHealthChecks, which both touch this.state.nodes. + activities.assignNodesToJob( + new ClusterManagerActivities.AssignNodesToJobInput(nodesToAssign, input.getJobName())); + for (String node : nodesToAssign) { + state.nodes.put(node, Optional.of(input.getJobName())); + } + state.jobAssigned.add(input.getJobName()); + return new ClusterManagerAssignNodesToJobResult(nodesToAssign); + } finally { + nodeLock.unlock(); + } + } + + @Override + public void deleteJob(ClusterManagerDeleteJobInput input) { + Workflow.await(() -> state.workflowState != ClusterState.NOT_STARTED); + if (state.workflowState == ClusterState.SHUTTING_DOWN) { + // If you want the client to receive a failure, either add an update validator and throw the + // exception from there, or raise an ApplicationFailure. Other exceptions in the main handler + // will cause the workflow to keep retrying and get it stuck. + throw ApplicationFailure.newFailure( + "Cannot delete a job: Cluster is already shut down", "IllegalState"); + } + nodeLock.lock(); + try { + Set nodesToUnassign = getAssignedNodes(input.getJobName()); + // This call would be dangerous without nodesLock because it yields control and allows + // interleaving + // with assignNodesToJob and performHealthChecks, which all touch this.state.nodes. + activities.unassignNodesForJob( + new ClusterManagerActivities.UnassignNodesForJobInput( + nodesToUnassign, input.getJobName())); + for (String node : nodesToUnassign) { + state.nodes.put(node, Optional.empty()); + } + } finally { + nodeLock.unlock(); + } + } + + private Set getAssignedNodes(String jobName) { + if (jobName != null) { + return state.nodes.entrySet().stream() + .filter(e -> e.getValue().isPresent() && e.getValue().get().equals(jobName)) + .map(e -> e.getKey()) + .collect(Collectors.toSet()); + } else { + return state.nodes.entrySet().stream() + .filter(e -> e.getValue().isPresent() && !e.getValue().get().equals("BAD!")) + .map(e -> e.getKey()) + .collect(Collectors.toSet()); + } + } + + private Set getUnassignedNodes() { + return state.nodes.entrySet().stream() + .filter(e -> !e.getValue().isPresent()) + .map(e -> e.getKey()) + .collect(Collectors.toSet()); + } + + private Set getBadNodes() { + return state.nodes.entrySet().stream() + .filter(e -> e.getValue().isPresent() && e.getValue().get().equals("BAD!")) + .map(e -> e.getKey()) + .collect(Collectors.toSet()); + } + + private void performHealthChecks() { + nodeLock.lock(); + try { + Set assignedNodes = getAssignedNodes(null); + Set badNodes = + activities.findBadNodes(new ClusterManagerActivities.FindBadNodesInput(assignedNodes)); + for (String badNode : badNodes) { + state.nodes.put(badNode, Optional.of("BAD!")); + } + } catch (Exception e) { + logger.error("Health check failed", e); + } finally { + nodeLock.unlock(); + } + } + + private boolean shouldContinueAsNew() { + if (Workflow.getInfo().isContinueAsNewSuggested()) { + return true; + } + // This is just for ease-of-testing. In production, we trust temporal to tell us when to + // continue as new. + if (maxHistoryLength > 0 && Workflow.getInfo().getHistoryLength() > maxHistoryLength) { + return true; + } + return false; + } +} diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java new file mode 100644 index 000000000..ea3aa4437 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.safemessagepassing; + +import static io.temporal.samples.safemessagepassing.ClusterManagerWorkflowWorker.CLUSTER_MANAGER_WORKFLOW_ID; +import static io.temporal.samples.safemessagepassing.ClusterManagerWorkflowWorker.TASK_QUEUE; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.client.WorkflowUpdateStage; +import io.temporal.serviceclient.WorkflowServiceStubs; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClusterManagerWorkflowStarter { + + private static final Logger logger = LoggerFactory.getLogger(ClusterManagerWorkflowStarter.class); + + public static void main(String[] args) { + if (args.length > 1) { + System.err.println( + "Usage: java " + + ClusterManagerWorkflowStarter.class.getName() + + " "); + System.exit(1); + } + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + boolean shouldTestContinueAsNew = args.length > 0 ? Boolean.parseBoolean(args[0]) : false; + ClusterManagerWorkflow cluster = + client.newWorkflowStub( + ClusterManagerWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(TASK_QUEUE) + .setWorkflowId(CLUSTER_MANAGER_WORKFLOW_ID + "-" + UUID.randomUUID()) + .build()); + + logger.info("Starting cluster"); + WorkflowClient.start( + cluster::run, + new ClusterManagerWorkflow.ClusterManagerInput(Optional.empty(), shouldTestContinueAsNew)); + Duration delay = shouldTestContinueAsNew ? Duration.ofSeconds(10) : Duration.ofSeconds(1); + cluster.startCluster(); + logger.info("Assigning jobs to nodes..."); + List> + assignJobs = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + assignJobs.add( + WorkflowStub.fromTyped(cluster) + .startUpdate( + "assignNodesToJobs", + WorkflowUpdateStage.ACCEPTED, + ClusterManagerWorkflow.ClusterManagerAssignNodesToJobResult.class, + new ClusterManagerWorkflow.ClusterManagerAssignNodesToJobInput(2, "job" + i)) + .getResultAsync()); + } + assignJobs.forEach(CompletableFuture::join); + + logger.info("Sleeping for " + delay.getSeconds() + " seconds"); + try { + Thread.sleep(delay.toMillis()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + logger.info("Deleting jobs..."); + List> deleteJobs = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + deleteJobs.add( + WorkflowStub.fromTyped(cluster) + .startUpdate( + "deleteJob", + WorkflowUpdateStage.ACCEPTED, + Void.class, + new ClusterManagerWorkflow.ClusterManagerDeleteJobInput("job" + i)) + .getResultAsync()); + } + deleteJobs.forEach(CompletableFuture::join); + + logger.info("Stopping cluster..."); + cluster.stopCluster(); + + ClusterManagerWorkflow.ClusterManagerResult result = + cluster.run(new ClusterManagerWorkflow.ClusterManagerInput(Optional.empty(), false)); + logger.info( + "Cluster shut down successfully. It had " + + result.getNumCurrentlyAssignedNodes() + + " nodes assigned at the end."); + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java new file mode 100644 index 000000000..ae98968e4 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.safemessagepassing; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClusterManagerWorkflowWorker { + private static final Logger logger = LoggerFactory.getLogger(ClusterManagerWorkflowWorker.class); + static final String TASK_QUEUE = "ClusterManagerWorkflowTaskQueue"; + static final String CLUSTER_MANAGER_WORKFLOW_ID = "ClusterManagerWorkflow"; + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + WorkerFactory factory = WorkerFactory.newInstance(client); + final Worker worker = factory.newWorker(TASK_QUEUE); + worker.registerWorkflowImplementationTypes(ClusterManagerWorkflowImpl.class); + worker.registerActivitiesImplementations(new ClusterManagerActivitiesImpl()); + factory.start(); + logger.info("Worker started for task queue: " + TASK_QUEUE); + } +} diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/README.md b/core/src/main/java/io/temporal/samples/safemessagepassing/README.md new file mode 100644 index 000000000..bb442f946 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/README.md @@ -0,0 +1,22 @@ +# Safe Message Passing + +This sample shows off important techniques for handling signals and updates, aka messages. In particular, it illustrates how message handlers can interleave or not be completed before the workflow completes, and how you can manage that. + +* Here, using Workflow.await, signal and update handlers will only operate when the workflow is within a certain state--between clusterStarted and clusterShutdown. +* You can run start_workflow with an initializer signal that you want to run before anything else other than the workflow's constructor. This pattern is known as "signal-with-start." +* Message handlers can block and their actions can be interleaved with one another and with the main workflow. This can easily cause bugs, so you can use a lock to protect shared state from interleaved access. +* An "Entity" workflow, i.e. a long-lived workflow, periodically "continues as new". It must do this to prevent its history from growing too large, and it passes its state to the next workflow. You can check `Workflow.getInfo().isContinueAsNewSuggested()` to see when it's time. +* Most people want their message handlers to finish before the workflow run completes or continues as new. Use `Workflow.await(() -> Workflow.isEveryHandlerFinished())` to achieve this. +* Message handlers can be made idempotent. See update `ClusterManagerWorkflow.assignNodesToJobs`. + +First start the Worker: + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.safemessagepassing.ClusterManagerWorkflowWorker +``` + +Then in a different terminal window start the Workflow Execution: + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.safemessagepassing.ClusterManagerWorkflowStarter +``` diff --git a/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java b/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java new file mode 100644 index 000000000..382ea1107 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.safemessagepassing; + +import io.temporal.client.*; +import io.temporal.failure.ApplicationFailure; +import io.temporal.testing.TestWorkflowRule; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ClusterManagerWorkflowWorkerTest { + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(ClusterManagerWorkflowImpl.class) + .setActivityImplementations(new ClusterManagerActivitiesImpl()) + .build(); + + @Test + public void testSafeMessageHandler() throws ExecutionException, InterruptedException { + ClusterManagerWorkflow cluster = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + ClusterManagerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + CompletableFuture result = + WorkflowClient.execute( + cluster::run, new ClusterManagerWorkflow.ClusterManagerInput(Optional.empty(), false)); + + cluster.startCluster(); + + List> + assignJobs = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + assignJobs.add( + WorkflowStub.fromTyped(cluster) + .startUpdate( + "assignNodesToJobs", + WorkflowUpdateStage.ACCEPTED, + ClusterManagerWorkflow.ClusterManagerAssignNodesToJobResult.class, + new ClusterManagerWorkflow.ClusterManagerAssignNodesToJobInput(2, "job-" + i)) + .getResultAsync()); + } + assignJobs.forEach( + (f) -> { + try { + Assert.assertEquals(2, f.get().getNodesAssigned().size()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + }); + + testWorkflowRule.getTestEnvironment().sleep(Duration.ofSeconds(1)); + + List> deleteJobs = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + deleteJobs.add( + WorkflowStub.fromTyped(cluster) + .startUpdate( + "deleteJob", + WorkflowUpdateStage.ACCEPTED, + Void.class, + new ClusterManagerWorkflow.ClusterManagerDeleteJobInput("job-" + i)) + .getResultAsync()); + } + deleteJobs.forEach(CompletableFuture::join); + + cluster.stopCluster(); + Assert.assertEquals(0, result.get().getNumCurrentlyAssignedNodes()); + } + + @Test + public void testUpdateIdempotency() { + ClusterManagerWorkflow cluster = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + ClusterManagerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + CompletableFuture result = + WorkflowClient.execute( + cluster::run, new ClusterManagerWorkflow.ClusterManagerInput(Optional.empty(), false)); + + cluster.startCluster(); + + ClusterManagerWorkflow.ClusterManagerAssignNodesToJobResult result1 = + cluster.assignNodesToJobs( + new ClusterManagerWorkflow.ClusterManagerAssignNodesToJobInput(5, "test-job")); + + ClusterManagerWorkflow.ClusterManagerAssignNodesToJobResult result2 = + cluster.assignNodesToJobs( + new ClusterManagerWorkflow.ClusterManagerAssignNodesToJobInput(5, "test-job")); + + Assert.assertTrue(result1.getNodesAssigned().size() >= result2.getNodesAssigned().size()); + } + + @Test + public void testUpdateFailure() throws ExecutionException, InterruptedException { + ClusterManagerWorkflow cluster = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + ClusterManagerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + CompletableFuture result = + WorkflowClient.execute( + cluster::run, new ClusterManagerWorkflow.ClusterManagerInput(Optional.empty(), false)); + + cluster.startCluster(); + + cluster.assignNodesToJobs( + new ClusterManagerWorkflow.ClusterManagerAssignNodesToJobInput(24, "big-job")); + WorkflowUpdateException updateFailure = + Assert.assertThrows( + WorkflowUpdateException.class, + () -> + cluster.assignNodesToJobs( + new ClusterManagerWorkflow.ClusterManagerAssignNodesToJobInput( + 3, "little-job"))); + Assert.assertTrue(updateFailure.getCause() instanceof ApplicationFailure); + Assert.assertEquals( + "Cannot assign nodes to a job: Not enough nodes available", + ((ApplicationFailure) updateFailure.getCause()).getOriginalMessage()); + + cluster.stopCluster(); + Assert.assertEquals( + 24, result.get().getNumCurrentlyAssignedNodes() + result.get().getNumBadNodes()); + } +} From 56fb8d7da69af65310f527146bf32d9a9a4eed27 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 4 Nov 2024 08:28:55 -0800 Subject: [PATCH 202/240] Add sample showing AWS encryption SDK (#700) Add sample showing AWS encryption SDK --- README.md | 5 + core/build.gradle | 7 + .../temporal/samples/hello/HelloActivity.java | 2 +- .../awsencryptionsdk/EncryptedPayloads.java | 91 ++++++++++ .../awsencryptionsdk/KeyringCodec.java | 162 ++++++++++++++++++ .../awsencryptionsdk/README.md | 28 +++ 6 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java create mode 100644 core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/KeyringCodec.java create mode 100644 core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/README.md diff --git a/README.md b/README.md index ebc558209..ea4a0f263 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,11 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Set up OpenTracing and/or OpenTelemetry with Jaeger**](/core/src/main/java/io/temporal/samples/tracing): Demonstrates how to set up OpenTracing and/or OpenTelemetry and view traces using Jaeger. +#### Encryption Support + +- [**Encrypted Payloads**](/core/src/main/java/io/temporal/samples/encryptedpayloads): Demonstrates how to use simple codec to encrypt and decrypt payloads. + +- [**AWS Encryption SDK**](/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk): Demonstrates how to use the AWS Encryption SDK to encrypt and decrypt payloads with AWS KMS. diff --git a/core/build.gradle b/core/build.gradle index b4653f828..42ad4be2b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -30,6 +30,13 @@ dependencies { implementation group: 'net.thisptr', name: 'jackson-jq', version: '1.0.0-preview.20240207' implementation group: 'commons-cli', name: 'commons-cli', version: '1.9.0' + // Used in AWS Encryption SDK sample + implementation group: 'com.amazonaws', name: 'aws-encryption-sdk-java', version: '3.0.1' + implementation("software.amazon.cryptography:aws-cryptographic-material-providers:1.0.2") + implementation(platform("software.amazon.awssdk:bom:2.20.91")) + implementation("software.amazon.awssdk:kms") + implementation("software.amazon.awssdk:dynamodb") + // we don't update it to 2.1.0 because 2.1.0 requires Java 11 implementation 'com.codingrodent:jackson-json-crypto:1.1.0' diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java index 9e46dfe63..70f2ebfa0 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java @@ -108,7 +108,7 @@ public String getGreeting(String name) { } /** Simple activity implementation, that concatenates two strings. */ - static class GreetingActivitiesImpl implements GreetingActivities { + public static class GreetingActivitiesImpl implements GreetingActivities { private static final Logger log = LoggerFactory.getLogger(GreetingActivitiesImpl.class); @Override diff --git a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java new file mode 100644 index 000000000..6052c9d7f --- /dev/null +++ b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.keymanagementencryption.awsencryptionsdk; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.converter.CodecDataConverter; +import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.samples.hello.HelloActivity; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import java.util.Collections; +import software.amazon.cryptography.materialproviders.IKeyring; +import software.amazon.cryptography.materialproviders.MaterialProviders; +import software.amazon.cryptography.materialproviders.model.CreateAwsKmsMultiKeyringInput; +import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig; + +public class EncryptedPayloads { + + static final String TASK_QUEUE = "EncryptedPayloads"; + + public static void main(String[] args) { + // Configure your keyring. In this sample we are configuring a basic AWS KMS keyring, but the + // AWS encryption SDK has multiple options depending on your use case. + // + // See more here: + // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/which-keyring.html + String generatorKey = System.getenv("AWS_KEY_ARN"); + + final MaterialProviders materialProviders = + MaterialProviders.builder() + .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) + .build(); + // Create the AWS KMS keyring + final CreateAwsKmsMultiKeyringInput keyringInput = + CreateAwsKmsMultiKeyringInput.builder().generator(generatorKey).build(); + final IKeyring kmsKeyring = materialProviders.CreateAwsKmsMultiKeyring(keyringInput); + // gRPC stubs wrapper that talks to the local docker instance of temporal service. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // client that can be used to start and signal workflows + WorkflowClient client = + WorkflowClient.newInstance( + service, + WorkflowClientOptions.newBuilder() + .setDataConverter( + new CodecDataConverter( + DefaultDataConverter.newDefaultInstance(), + // Create our encryption codec + Collections.singletonList(new KeyringCodec(kmsKeyring)))) + .build()); + + // worker factory that can be used to create workers for specific task queues + WorkerFactory factory = WorkerFactory.newInstance(client); + // Worker that listens on a task queue and hosts both workflow and activity implementations. + Worker worker = factory.newWorker(TASK_QUEUE); + // Register the workflows and activities + worker.registerWorkflowImplementationTypes(HelloActivity.GreetingWorkflowImpl.class); + worker.registerActivitiesImplementations(new HelloActivity.GreetingActivitiesImpl()); + // Start listening to the workflow and activity task queues. + factory.start(); + + // Start a workflow execution. + HelloActivity.GreetingWorkflow workflow = + client.newWorkflowStub( + HelloActivity.GreetingWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build()); + // Execute a workflow waiting for it to complete. + String greeting = workflow.getGreeting("My Secret Friend"); + System.out.println(greeting); + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/KeyringCodec.java b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/KeyringCodec.java new file mode 100644 index 000000000..e8d669408 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/KeyringCodec.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.keymanagementencryption.awsencryptionsdk; + +import com.amazonaws.encryptionsdk.AwsCrypto; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import io.temporal.api.common.v1.Payload; +import io.temporal.common.converter.EncodingKeys; +import io.temporal.payload.codec.PayloadCodec; +import io.temporal.payload.context.ActivitySerializationContext; +import io.temporal.payload.context.HasWorkflowSerializationContext; +import io.temporal.payload.context.SerializationContext; +import io.temporal.workflow.unsafe.WorkflowUnsafe; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.jetbrains.annotations.NotNull; +import software.amazon.cryptography.materialproviders.IKeyring; + +/** + * KeyringCodec is a {@link PayloadCodec} that encrypts and decrypts payloads using the AWS + * Encryption SDK. It uses the provided {@link IKeyring} to encrypt and decrypt payloads. It can + * optionally support using a {@link SerializationContext}. + */ +class KeyringCodec implements PayloadCodec { + // Metadata encoding key for the AWS Encryption SDK + static final ByteString METADATA_ENCODING = + ByteString.copyFrom("awsencriptionsdk/binary/encrypted", StandardCharsets.UTF_8); + + private final AwsCrypto crypto; + private final IKeyring kmsKeyring; + private final boolean useSerializationContext; + @Nullable private final SerializationContext serializationContext; + + /** + * Constructs a new KeyringCodec with the provided {@link IKeyring}. The codec will not use a + * {@link SerializationContext}. + * + * @param kmsKeyring the keyring to use for encryption and decryption. + */ + public KeyringCodec(IKeyring kmsKeyring) { + this.crypto = AwsCrypto.standard(); + this.kmsKeyring = kmsKeyring; + this.useSerializationContext = false; + this.serializationContext = null; + } + + /** + * Constructs a new KeyringCodec with the provided {@link IKeyring}. + * + * @param crypto the AWS Crypto object to use for encryption and decryption. + * @param kmsKeyring the keyring to use for encryption and decryption. + * @param useSerializationContext whether to use a {@link SerializationContext} for encoding and + * decoding payloads. + */ + public KeyringCodec(AwsCrypto crypto, IKeyring kmsKeyring, boolean useSerializationContext) { + this.crypto = crypto; + this.kmsKeyring = kmsKeyring; + this.useSerializationContext = useSerializationContext; + this.serializationContext = null; + } + + private KeyringCodec( + AwsCrypto crypto, IKeyring kmsKeyring, SerializationContext serializationContext) { + this.crypto = crypto; + this.kmsKeyring = kmsKeyring; + this.useSerializationContext = true; + this.serializationContext = serializationContext; + } + + @NotNull + @Override + public List encode(@NotNull List payloads) { + // Disable deadlock detection for encoding payloads because this may make a network call + // to encrypt the data. + return WorkflowUnsafe.deadlockDetectorOff( + () -> payloads.stream().map(this::encodePayload).collect(Collectors.toList())); + } + + @NotNull + @Override + public List decode(@NotNull List payloads) { + // Disable deadlock detection for decoding payloads because this may make a network call + // to decrypt the data. + return WorkflowUnsafe.deadlockDetectorOff( + () -> payloads.stream().map(this::decodePayload).collect(Collectors.toList())); + } + + @NotNull + @Override + public PayloadCodec withContext(@Nonnull SerializationContext context) { + if (!useSerializationContext) { + return this; + } + return new KeyringCodec(crypto, kmsKeyring, context); + } + + private Map getEncryptionContext() { + // If we are not using a serialization context, return an empty map + // There may not be a serialization context if certain cases, such as when the codec is used + // for encoding/decoding payloads for a Nexus operation. + if (!useSerializationContext + || serializationContext == null + || !(serializationContext instanceof HasWorkflowSerializationContext)) { + return Collections.emptyMap(); + } + String workflowId = ((HasWorkflowSerializationContext) serializationContext).getWorkflowId(); + String activityType = null; + if (serializationContext instanceof ActivitySerializationContext) { + activityType = ((ActivitySerializationContext) serializationContext).getActivityType(); + } + String signature = activityType != null ? workflowId + activityType : workflowId; + return Collections.singletonMap("signature", signature); + } + + private Payload encodePayload(Payload payload) { + byte[] plaintext = payload.toByteArray(); + byte[] ciphertext = + crypto.encryptData(kmsKeyring, plaintext, getEncryptionContext()).getResult(); + return Payload.newBuilder() + .setData(ByteString.copyFrom(ciphertext)) + .putMetadata(EncodingKeys.METADATA_ENCODING_KEY, METADATA_ENCODING) + .build(); + } + + private Payload decodePayload(Payload payload) { + if (METADATA_ENCODING.equals( + payload.getMetadataOrDefault(EncodingKeys.METADATA_ENCODING_KEY, null))) { + byte[] ciphertext = payload.getData().toByteArray(); + byte[] plaintext = + crypto.decryptData(kmsKeyring, ciphertext, getEncryptionContext()).getResult(); + try { + return Payload.parseFrom(plaintext); + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(e); + } + } + return payload; + } +} diff --git a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/README.md b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/README.md new file mode 100644 index 000000000..71ee37e7c --- /dev/null +++ b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/README.md @@ -0,0 +1,28 @@ +## AWS Encryption SDK Sample + +This sample demonstrates how a user can leverage the [AWS Encryption](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/java.html) SDK to build a `PayloadCodec` to encrypt and decrypt payloads using [AWS KMS](https://aws.amazon.com/kms/) and envelope encryption. + +### About the AWS Encryption SDK: + +>The AWS Encryption SDK is a client-side encryption library designed to make it easy for everyone to encrypt and decrypt data using industry standards and best practices. It enables you to focus on the core functionality of your application, rather than on how to best encrypt and decrypt your data. The AWS Encryption SDK is provided free of charge under the Apache 2.0 license. + +For more details please see [Amazons Documentation](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html) + +### Choosing a Key Ring + +This sample uses am [AWS KMS keyring](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html). This approach is convenient as you don't need to manage or secure your own keys. One drawback of this approach is it will require a call to KMS every time you need encrypt or decrypt data. If this is a concern you may want to consider using an [AWS KMS Hierarchical keyring](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-hierarchical-keyring.html). + +Note: You can also use the AWS Encryption SDK without any AWS services using the raw keyrings. + +For more details please see [Amazons Documentation on choosing a key ring](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/which-keyring.html). + +### Running this sample + +Make sure your AWS account credentials are up-to-date and can access KMS. + +Export the following environment variables +- `AWS_KEY_ARN`: Your AWS key ARN. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.keymanagementencryption.awsencryptionsdk.EncryptedPayloads +``` From dcee476eeabe24b7474ea0f2da5f80deed26bebb Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 5 Nov 2024 07:55:00 -0800 Subject: [PATCH 203/240] Fix formatting (#701) --- .../samples/safemessagepassing/ClusterManagerWorkflow.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java index 52ab24476..afe42b37c 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java @@ -40,6 +40,7 @@ enum ClusterState { STARTED, SHUTTING_DOWN } + // In workflows that continue-as-new, it's convenient to store all your state in one serializable // structure to make it easier to pass between runs class ClusterManagerState { From 69db54524cccd94634cd81a551c724312e74c471 Mon Sep 17 00:00:00 2001 From: Stephan Behnke Date: Tue, 10 Dec 2024 12:08:18 -0800 Subject: [PATCH 204/240] Update Java SDK (#705) --- build.gradle | 2 +- .../SimpleCountWorkerInterceptor.java | 6 +-- .../earlyreturn/EarlyReturnClient.java | 16 +++--- .../interceptor/MyWorkerInterceptor.java | 6 +-- .../RetryOnSignalWorkerInterceptor.java | 6 +-- .../earlyreturn/TransactionWorkflowTest.java | 52 +++++++++---------- .../ClusterManagerWorkflowWorkerTest.java | 5 +- 7 files changed, 40 insertions(+), 53 deletions(-) diff --git a/build.gradle b/build.gradle index 43c50ce5b..92d13ca62 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.26.1' + javaSDKVersion = '1.27.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java index 268d2620a..156002e42 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java @@ -19,11 +19,9 @@ package io.temporal.samples.countinterceptor; -import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; -import io.temporal.common.interceptors.WorkerInterceptor; -import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; +import io.temporal.common.interceptors.*; -public class SimpleCountWorkerInterceptor implements WorkerInterceptor { +public class SimpleCountWorkerInterceptor extends WorkerInterceptorBase { @Override public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) { diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java index 6ccb11da1..36da78d87 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java @@ -19,6 +19,7 @@ package io.temporal.samples.earlyreturn; +import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; import io.temporal.client.*; import io.temporal.serviceclient.WorkflowServiceStubs; @@ -49,17 +50,13 @@ private static void runWorkflowWithUpdateWithStart(WorkflowClient client) { System.out.println("Starting workflow with UpdateWithStart"); - UpdateWithStartWorkflowOperation updateOp = - UpdateWithStartWorkflowOperation.newBuilder(workflow::returnInitResult) - .setWaitForStage(WorkflowUpdateStage.COMPLETED) // Wait for update to complete - .build(); - TxResult updateResult = null; try { - WorkflowUpdateHandle updateHandle = - WorkflowClient.updateWithStart(workflow::processTransaction, txRequest, updateOp); - - updateResult = updateHandle.getResultAsync().get(); + updateResult = + WorkflowClient.executeUpdateWithStart( + workflow::returnInitResult, + UpdateOptions.newBuilder().build(), + new WithStartWorkflowOperation<>(workflow::processTransaction, txRequest)); System.out.println( "Workflow initialized with result: " @@ -84,6 +81,7 @@ private static void runWorkflowWithUpdateWithStart(WorkflowClient client) { private static WorkflowOptions buildWorkflowOptions() { return WorkflowOptions.newBuilder() .setTaskQueue(TASK_QUEUE) + .setWorkflowIdConflictPolicy(WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_FAIL) .setWorkflowId(WORKFLOW_ID_PREFIX + System.currentTimeMillis()) .build(); } diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java index 7674013dc..761f39b70 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java @@ -19,13 +19,11 @@ package io.temporal.samples.excludefrominterceptor.interceptor; -import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; -import io.temporal.common.interceptors.WorkerInterceptor; -import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; +import io.temporal.common.interceptors.*; import java.util.ArrayList; import java.util.List; -public class MyWorkerInterceptor implements WorkerInterceptor { +public class MyWorkerInterceptor extends WorkerInterceptorBase { private List excludeWorkflowTypes = new ArrayList<>(); private List excludeActivityTypes = new ArrayList<>(); diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java index 6e4ba7db0..180306447 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java @@ -19,12 +19,10 @@ package io.temporal.samples.retryonsignalinterceptor; -import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; -import io.temporal.common.interceptors.WorkerInterceptor; -import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; +import io.temporal.common.interceptors.*; /** Should be registered through WorkerFactoryOptions. */ -public class RetryOnSignalWorkerInterceptor implements WorkerInterceptor { +public class RetryOnSignalWorkerInterceptor extends WorkerInterceptorBase { @Override public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) { return new RetryOnSignalWorkflowInboundCallsInterceptor(next); diff --git a/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java b/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java index 5661d28a9..97cda3583 100644 --- a/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java @@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; +import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; import io.temporal.client.*; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; @@ -63,23 +64,22 @@ public void testUpdateWithStartValidAmount() throws Exception { TransactionWorkflow workflow = workflowClient.newWorkflowStub( TransactionWorkflow.class, - WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); - - // Create update operation - UpdateWithStartWorkflowOperation updateOp = - UpdateWithStartWorkflowOperation.newBuilder(workflow::returnInitResult) - .setWaitForStage(WorkflowUpdateStage.COMPLETED) - .build(); + WorkflowOptions.newBuilder() + .setWorkflowIdConflictPolicy( + WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_FAIL) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build()); // Execute UpdateWithStart - WorkflowUpdateHandle handle = - WorkflowClient.updateWithStart( - workflow::processTransaction, - new TransactionRequest(SOURCE_ACCOUNT, TARGET_ACCOUNT, VALID_AMOUNT), - updateOp); + TransactionRequest txRequest = + new TransactionRequest(SOURCE_ACCOUNT, TARGET_ACCOUNT, VALID_AMOUNT); + TxResult updateResult = + WorkflowClient.executeUpdateWithStart( + workflow::returnInitResult, + UpdateOptions.newBuilder().build(), + new WithStartWorkflowOperation<>(workflow::processTransaction, txRequest)); // Verify both update and final results - TxResult updateResult = handle.getResultAsync().get(); assertEquals(TEST_TRANSACTION_ID, updateResult.getTransactionId()); TxResult finalResult = WorkflowStub.fromTyped(workflow).getResult(TxResult.class); @@ -111,6 +111,7 @@ public void testUpdateWithStartInvalidAmount() throws Exception { String workflowId = "test-workflow-" + UUID.randomUUID(); WorkflowOptions options = WorkflowOptions.newBuilder() + .setWorkflowIdConflictPolicy(WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_FAIL) .setTaskQueue(testWorkflowRule.getTaskQueue()) .setWorkflowId(workflowId) .build(); @@ -118,26 +119,21 @@ public void testUpdateWithStartInvalidAmount() throws Exception { TransactionWorkflow workflow = workflowClient.newWorkflowStub(TransactionWorkflow.class, options); - // Create update operation - UpdateWithStartWorkflowOperation updateOp = - UpdateWithStartWorkflowOperation.newBuilder(workflow::returnInitResult) - .setWaitForStage(WorkflowUpdateStage.COMPLETED) - .build(); - // Execute UpdateWithStart and expect the exception - WorkflowServiceException exception = + TransactionRequest txRequest = + new TransactionRequest(SOURCE_ACCOUNT, TARGET_ACCOUNT, INVALID_AMOUNT); + WorkflowUpdateException exception = assertThrows( - WorkflowServiceException.class, + WorkflowUpdateException.class, () -> - WorkflowClient.updateWithStart( - workflow::processTransaction, - new TransactionRequest(SOURCE_ACCOUNT, TARGET_ACCOUNT, INVALID_AMOUNT), - updateOp)); + WorkflowClient.executeUpdateWithStart( + workflow::returnInitResult, + UpdateOptions.newBuilder().build(), + new WithStartWorkflowOperation<>(workflow::processTransaction, txRequest))); // Verify the exception chain - assertTrue(exception.getCause() instanceof WorkflowUpdateException); - assertTrue(exception.getCause().getCause() instanceof ActivityFailure); - ApplicationFailure appFailure = (ApplicationFailure) exception.getCause().getCause().getCause(); + assertTrue(exception.getCause() instanceof ActivityFailure); + ApplicationFailure appFailure = (ApplicationFailure) exception.getCause().getCause(); assertEquals("InvalidAmount", appFailure.getType()); assertTrue(appFailure.getMessage().contains("Invalid Amount")); diff --git a/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java b/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java index 382ea1107..55ea41fd9 100644 --- a/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java +++ b/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java @@ -105,9 +105,8 @@ public void testUpdateIdempotency() { .newWorkflowStub( ClusterManagerWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); - CompletableFuture result = - WorkflowClient.execute( - cluster::run, new ClusterManagerWorkflow.ClusterManagerInput(Optional.empty(), false)); + WorkflowClient.execute( + cluster::run, new ClusterManagerWorkflow.ClusterManagerInput(Optional.empty(), false)); cluster.startCluster(); From 30db7dba46b5879ff64929749ccb54201addfd4e Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 31 Dec 2024 16:56:47 +0100 Subject: [PATCH 205/240] Workflow timer sample (#708) Signed-off-by: Tihomir Surdilovic --- README.md | 1 + .../samples/hello/HelloWorkflowTimer.java | 253 ++++++++++++++++++ .../samples/hello/HelloWorkflowTimerTest.java | 53 ++++ 3 files changed, 307 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java diff --git a/README.md b/README.md index ea4a0f263..b30743697 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloUpdate**](/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java): Demonstrates how to create and interact with an Update. - [**HelloDelayedStart**](/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java): Demonstrates how to use delayed start config option when starting a Workflow Executions. - [**HelloSignalWithTimer**](/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java): Demonstrates how to use collect signals for certain amount of time and then process last one. + - [**HelloWorkflowTimer**](/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java): Demonstrates how we can use workflow timer to restrict duration of workflow execution instead of workflow run/execution timeouts. #### Scenario-based samples diff --git a/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java new file mode 100644 index 000000000..a03a8104b --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.activity.*; +import io.temporal.client.ActivityCompletionException; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.CanceledFailure; +import io.temporal.failure.ChildWorkflowFailure; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.workflow.*; +import java.time.Duration; + +/** Sample shows how to use workflow timer instead of WorkflowOptions->Run/ExecutionTimeout */ +public class HelloWorkflowTimer { + private static String WORKFLOW_ID = "HelloWorkflowWithTimer"; + private static String TASK_QUEUE = "HelloWorkflowWithTimerTaskQueue"; + // Change time to 12 to 20 seconds to handle cancellation while child workflow is running + private static int TIME_SECS = 8; + + // Workflow + @WorkflowInterface + public interface WorkflowWithTimer { + @WorkflowMethod + String execute(String input); + } + + public static class WorkflowWithTimerImpl implements WorkflowWithTimer { + // Our timer cancellation scope + private CancellationScope timerCancellationScope; + // Our workflow cancellation scope + private CancellationScope workflowCancellationScope; + // Workflow result + private String workflowResult = ""; + private Promise workflowTimerPromise; + + @Override + public String execute(String input) { + // Create workflow timer (within timer cancel;ation scope so it can be canceled) + // which denotes the max amount of time we allow this execution to run + // Using workflow timer instead of workflow run/execution timeouts allow us to react to this + // timer + // fires, be able to chose if we want to fail or complete execution, and do some "cleanup" + // tasks if + // necessary before we do so. If we used workflow run/execution timeouts insted we would not + // be able + // to react to this timer firing (its server timer only) + timerCancellationScope = + Workflow.newCancellationScope( + () -> { + workflowTimerPromise = + Workflow.newTimer( + Duration.ofSeconds(TIME_SECS), + TimerOptions.newBuilder().setSummary("Workflow Timer").build()) + // We can use thenApply here to cancel our cancelation scope when this timer + // fires. Note we cannot complete the execution from here, see + // https://github.com/temporalio/sdk-java/issues/87 + .thenApply( + ignore -> { + // Cancel the workflow cancellation scope allowing us to react to this + // timer firing + if (workflowCancellationScope != null) { + workflowCancellationScope.cancel("Workflow timer fired"); + } + return null; + }); + }); + timerCancellationScope.run(); + + // Create workflow cancellation scope in which we put our core business logic + workflowCancellationScope = + Workflow.newCancellationScope( + () -> { + WorkflowWithTimerActivities activities = + Workflow.newActivityStub( + WorkflowWithTimerActivities.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(12)) + // Set heartbeat timeout to 1s + .setHeartbeatTimeout(Duration.ofSeconds(2)) + // We want to wait for activity to complete cancellation + .setCancellationType( + ActivityCancellationType.WAIT_CANCELLATION_COMPLETED) + .build()); + + WorkflowWithTimerChildWorkflow childWorkflow = + Workflow.newChildWorkflowStub( + WorkflowWithTimerChildWorkflow.class, + ChildWorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID + "-Child") + // We want to wait for child workflow cancellation completion + .setCancellationType( + ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED) + .build()); + + try { + // Run our activities + workflowResult = activities.sayHello(input); + // Then our child workflow + childWorkflow.executeChild(input); + } catch (ActivityFailure af) { + // Handle cancellation of scope while activities are pending (running) + if (af.getCause() instanceof CanceledFailure) { + workflowResult = "Workflow timer fired while activities were executing."; + // Here we can do more work if needed + } + } catch (ChildWorkflowFailure cwf) { + // Handle cancellation of scope while child workflow is pending (running) + if (cwf.getCause() instanceof CanceledFailure) { + workflowResult = "Workflow timer fired while child workflow was executing."; + // Here we can do more work if needed + } + } + }); + // Run the workflow cancellation scope + // We need to handle CanceledFailure here in case we cancel the scope + // right before activity/child workflows are scheduled + try { + workflowCancellationScope.run(); + } catch (CanceledFailure e) { + workflowResult = "Workflow cancelled."; + } + + // Cancel our workflow timer if it didnt fire + if (!workflowTimerPromise.isCompleted()) { + timerCancellationScope.cancel("Workflow completed before workflow timer."); + } + + return workflowResult; + } + } + + // Activities + @ActivityInterface + public interface WorkflowWithTimerActivities { + String sayHello(String input); + } + + public static class WorkflowWithTimerActivitiesImpl implements WorkflowWithTimerActivities { + @Override + public String sayHello(String input) { + // here we just heartbeat then sleep for 1s + for (int i = 0; i < 10; i++) { + try { + Activity.getExecutionContext().heartbeat("heartbeating: " + i); + } catch (ActivityCompletionException e) { + // Do some cleanup if needed, then re-throw + throw e; + } + sleep(1); + } + return "Hello " + input; + } + + // Just sample sleep method + private void sleep(int seconds) { + try { + Thread.sleep(seconds * 1000L); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + } + + // Child Workflows + @WorkflowInterface + public interface WorkflowWithTimerChildWorkflow { + @WorkflowMethod + String executeChild(String input); + } + + public static class WorkflowWithTimerChildWorkflowImpl implements WorkflowWithTimerChildWorkflow { + @Override + public String executeChild(String input) { + // For sample we just sleep for 5 seconds and return some result + try { + Workflow.sleep(Duration.ofSeconds(5)); + return "From executeChild - " + input; + // Note that similarly to parent workflow if child is running activities/child workflows + // we need to handle this in same way as parent does + // Fpr sample we can just handle CanceledFailure and rethrow + } catch (CanceledFailure e) { + // Can do cleanup if needed + throw e; + } + } + } + + public static void main(String[] args) { + // Create service stubs + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Crete workflow client + WorkflowClient client = WorkflowClient.newInstance(service); + // Create worker factory + WorkerFactory factory = WorkerFactory.newInstance(client); + + // Create worker + Worker worker = factory.newWorker(TASK_QUEUE); + // Register workflow and child workflow + worker.registerWorkflowImplementationTypes( + WorkflowWithTimerImpl.class, WorkflowWithTimerChildWorkflowImpl.class); + // Register activities + worker.registerActivitiesImplementations(new WorkflowWithTimerActivitiesImpl()); + + // Start factory (and worker) + factory.start(); + + // Create workflow stub + WorkflowWithTimer workflow = + client.newWorkflowStub( + WorkflowWithTimer.class, + WorkflowOptions.newBuilder() + // Note we do not set workflow run/execution timeouts + // As its not recommended in most cases + // In same we show how we can implement this with workflow timer instead + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + // Start workflow execution async + WorkflowClient.start(workflow::execute, "Some Name Here"); + + // Wait for execution to complete (sync) + WorkflowStub workflowStub = WorkflowStub.fromTyped(workflow); + String result = workflowStub.getResult(String.class); + System.out.println("Workflow result: " + result); + + // Stop main method + System.exit(0); + } +} diff --git a/core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java b/core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java new file mode 100644 index 000000000..7e0954494 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.hello; + +import io.temporal.client.WorkflowOptions; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class HelloWorkflowTimerTest { + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes( + HelloWorkflowTimer.WorkflowWithTimerImpl.class, + HelloWorkflowTimer.WorkflowWithTimerChildWorkflowImpl.class) + .setActivityImplementations(new HelloWorkflowTimer.WorkflowWithTimerActivitiesImpl()) + .build(); + + @Test + public void testWorkflowTimer() { + HelloWorkflowTimer.WorkflowWithTimer workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloWorkflowTimer.WorkflowWithTimer.class, + WorkflowOptions.newBuilder() + .setWorkflowId("WorkflowWithTimerTestId") + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build()); + + String result = workflow.execute("test input"); + Assert.assertEquals("Workflow timer fired while activities were executing.", result); + } +} From 1b1a6321761143d21580532d8ba0ae2044b230d7 Mon Sep 17 00:00:00 2001 From: Thomas Hardy Date: Fri, 31 Jan 2025 09:32:31 -0800 Subject: [PATCH 206/240] Add sleepfordays sample (#709) * Add sleepfordays sample * remove extra semicolon --- .../temporal/samples/sleepfordays/README.md | 17 ++++ .../sleepfordays/SendEmailActivity.java | 27 +++++++ .../sleepfordays/SendEmailActivityImpl.java | 27 +++++++ .../sleepfordays/SleepForDaysImpl.java | 54 +++++++++++++ .../sleepfordays/SleepForDaysWorkflow.java | 33 ++++++++ .../samples/sleepfordays/Starter.java | 46 +++++++++++ .../temporal/samples/sleepfordays/Worker.java | 40 ++++++++++ .../sleepfordays/SleepForDaysTest.java | 80 +++++++++++++++++++ 8 files changed, 324 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/sleepfordays/README.md create mode 100644 core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java create mode 100644 core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java create mode 100644 core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java create mode 100644 core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/sleepfordays/Starter.java create mode 100644 core/src/main/java/io/temporal/samples/sleepfordays/Worker.java create mode 100644 core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysTest.java diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/README.md b/core/src/main/java/io/temporal/samples/sleepfordays/README.md new file mode 100644 index 000000000..a8800033d --- /dev/null +++ b/core/src/main/java/io/temporal/samples/sleepfordays/README.md @@ -0,0 +1,17 @@ +# Sleep for days + +This sample demonstrates how to use Temporal to run a workflow that periodically sleeps for a number of days. + +## Run the sample + +1. Start the Worker: + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.sleepfordays.Worker +``` + +2. Start the Starter + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.sleepfordays.Starter +``` \ No newline at end of file diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java b/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java new file mode 100644 index 000000000..94eba7746 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.sleepfordays; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface SendEmailActivity { + void sendEmail(String email); +} diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java b/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java new file mode 100644 index 000000000..a8cd72536 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.sleepfordays; + +public class SendEmailActivityImpl implements SendEmailActivity { + @Override + public void sendEmail(String email) { + System.out.println(email); + } +} diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java b/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java new file mode 100644 index 000000000..2828a3ada --- /dev/null +++ b/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.sleepfordays; + +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class SleepForDaysImpl implements SleepForDaysWorkflow { + + private final SendEmailActivity activity; + private boolean complete = false; + + public SleepForDaysImpl() { + this.activity = + Workflow.newActivityStub( + SendEmailActivity.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build()); + } + + @Override + public String sleepForDays() { + while (!this.complete) { + activity.sendEmail(String.format("Sleeping for 30 days")); + Promise timer = Workflow.newTimer(Duration.ofDays(30)); + Workflow.await(() -> timer.isCompleted() || this.complete); + } + + return "done!"; + } + + @Override + public void complete() { + this.complete = true; + } +} diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java b/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java new file mode 100644 index 000000000..1bced9729 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.sleepfordays; + +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface SleepForDaysWorkflow { + @WorkflowMethod + String sleepForDays(); + + @SignalMethod + void complete(); +} diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java b/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java new file mode 100644 index 000000000..a9660de7c --- /dev/null +++ b/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.sleepfordays; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; + +public class Starter { + + public static final String TASK_QUEUE = "SleepForDaysTaskQueue"; + + public static void main(String[] args) { + // Start a workflow execution. + SleepForDaysWorkflow workflow = + Worker.client.newWorkflowStub( + SleepForDaysWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build()); + + // Start the workflow. + WorkflowClient.start(workflow::sleepForDays); + + WorkflowStub stub = WorkflowStub.fromTyped(workflow); + + // Wait for workflow to complete. This will wait indefinitely until a 'complete' signal is sent. + stub.getResult(String.class); + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java b/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java new file mode 100644 index 000000000..28ae326cc --- /dev/null +++ b/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.sleepfordays; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.WorkerFactory; + +public class Worker { + public static final String TASK_QUEUE = "SleepForDaysTaskQueue"; + public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + public static final WorkflowClient client = WorkflowClient.newInstance(service); + public static final WorkerFactory factory = WorkerFactory.newInstance(client); + + public static void main(String[] args) { + io.temporal.worker.Worker worker = factory.newWorker(TASK_QUEUE); + worker.registerWorkflowImplementationTypes(SleepForDaysImpl.class); + worker.registerActivitiesImplementations(new SendEmailActivityImpl()); + + factory.start(); + System.out.println("Worker started for task queue: " + TASK_QUEUE); + } +} diff --git a/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysTest.java b/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysTest.java new file mode 100644 index 000000000..c79ee0400 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.sleepfordays; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.testing.TestWorkflowRule; +import java.time.Duration; +import org.junit.Rule; +import org.junit.Test; + +public class SleepForDaysTest { + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(SleepForDaysImpl.class) + .setDoNotStart(true) + .build(); + + @Test(timeout = 8000) + public void testSleepForDays() { + // Mock activity + SendEmailActivity activities = mock(SendEmailActivity.class); + testWorkflowRule.getWorker().registerActivitiesImplementations(activities); + // Start environment + testWorkflowRule.getTestEnvironment().start(); + + // Create a workflow + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build(); + SleepForDaysWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(SleepForDaysWorkflow.class, workflowOptions); + + // Start workflow + WorkflowClient.start(workflow::sleepForDays); + + long startTime = testWorkflowRule.getTestEnvironment().currentTimeMillis(); + // Time-skip 5 minutes. + testWorkflowRule.getTestEnvironment().sleep(Duration.ofMinutes(5)); + // Check that the activity has been called, we're now waiting for the sleep to finish. + verify(activities, times(1)).sendEmail(anyString()); + // Time-skip 3 days. + testWorkflowRule.getTestEnvironment().sleep(Duration.ofDays(90)); + // Expect 3 more activity calls. + verify(activities, times(4)).sendEmail(anyString()); + // Send the signal to complete the workflow. + workflow.complete(); + // Expect no more activity calls to have been made - workflow is complete. + verify(activities, times(4)).sendEmail(anyString()); + // Expect more than 90 days to have passed. + long endTime = testWorkflowRule.getTestEnvironment().currentTimeMillis(); + assertEquals(true, endTime - startTime > Duration.ofDays(90).toMillis()); + } +} From 306cb17da725813340c09686ef785c1ead628ff7 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 26 Feb 2025 13:34:45 -0800 Subject: [PATCH 207/240] Update Nexus sample for v1.28.0 (#716) Update Nexus Sample for v1.28.0 --- build.gradle | 2 +- .../java/io/temporal/samples/nexus/README.MD | 4 +- .../samples/nexus/caller/CallerStarter.java | 20 ++++---- .../nexus/caller/HelloCallerWorkflowImpl.java | 2 +- .../nexus/handler/NexusServiceImpl.java | 50 ++++++++++--------- 5 files changed, 42 insertions(+), 36 deletions(-) diff --git a/build.gradle b/build.gradle index 92d13ca62..51b1a80e5 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.27.0' + javaSDKVersion = '1.28.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/core/src/main/java/io/temporal/samples/nexus/README.MD b/core/src/main/java/io/temporal/samples/nexus/README.MD index 526d3d486..9e848c6d8 100644 --- a/core/src/main/java/io/temporal/samples/nexus/README.MD +++ b/core/src/main/java/io/temporal/samples/nexus/README.MD @@ -24,7 +24,7 @@ This sample shows how to use Temporal for authoring a Nexus service and call it site](https://learn.temporal.io/getting_started/go/dev_environment/#set-up-a-local-temporal-service-for-development-with-temporal-cli) to install Temporal CLI. -> NOTE: Required version is at least v1.1.0. +> NOTE: he recommended version is at least v1.3.0. ### Spin up environment @@ -33,7 +33,7 @@ This sample shows how to use Temporal for authoring a Nexus service and call it > HTTP port is required for Nexus communications ``` -temporal server start-dev --http-port 7243 --dynamic-config-value system.enableNexus=true +temporal server start-dev ``` ### Initialize environment diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java index 23dd0f5ec..5c65df949 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java @@ -19,9 +19,9 @@ package io.temporal.samples.nexus.caller; +import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; -import io.temporal.client.WorkflowStub; import io.temporal.samples.nexus.options.ClientOptions; import io.temporal.samples.nexus.service.NexusService; import org.slf4j.Logger; @@ -37,17 +37,19 @@ public static void main(String[] args) { WorkflowOptions.newBuilder().setTaskQueue(CallerWorker.DEFAULT_TASK_QUEUE_NAME).build(); EchoCallerWorkflow echoWorkflow = client.newWorkflowStub(EchoCallerWorkflow.class, workflowOptions); - logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); + WorkflowExecution execution = WorkflowClient.start(echoWorkflow::echo, "Nexus Echo πŸ‘‹"); logger.info( - "Started workflow workflowId: {} runId: {}", - WorkflowStub.fromTyped(echoWorkflow).getExecution().getWorkflowId(), - WorkflowStub.fromTyped(echoWorkflow).getExecution().getRunId()); + "Started EchoCallerWorkflow workflowId: {} runId: {}", + execution.getWorkflowId(), + execution.getRunId()); + logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); HelloCallerWorkflow helloWorkflow = client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); - logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); logger.info( - "Started workflow workflowId: {} runId: {}", - WorkflowStub.fromTyped(helloWorkflow).getExecution().getWorkflowId(), - WorkflowStub.fromTyped(helloWorkflow).getExecution().getRunId()); + "Started HelloCallerWorkflow workflowId: {} runId: {}", + execution.getWorkflowId(), + execution.getRunId()); + logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); } } diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java index dcc8d1a04..5b9048d60 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java @@ -43,7 +43,7 @@ public String hello(String message, NexusService.Language language) { Workflow.startNexusOperation( nexusService::hello, new NexusService.HelloInput(message, language)); // Optionally wait for the operation to be started. NexusOperationExecution will contain the - // operation ID in case this operation is asynchronous. + // operation token in case this operation is asynchronous. handle.getExecution().get(); return handle.getResult().get().getMessage(); } diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java index 4d6cb3cad..d7fda2fd9 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java @@ -23,7 +23,8 @@ import io.nexusrpc.handler.OperationImpl; import io.nexusrpc.handler.ServiceImpl; import io.temporal.client.WorkflowOptions; -import io.temporal.nexus.WorkflowClientOperationHandlers; +import io.temporal.nexus.Nexus; +import io.temporal.nexus.WorkflowRunOperation; import io.temporal.samples.nexus.service.NexusService; // To create a service implementation, annotate the class with @ServiceImpl and provide the @@ -33,33 +34,36 @@ public class NexusServiceImpl { @OperationImpl public OperationHandler echo() { - // WorkflowClientOperationHandlers.sync is a meant for exposing simple RPC handlers. - return WorkflowClientOperationHandlers.sync( - // The method is provided with an SDK client that can be used for arbitrary calls such as - // signaling, querying, - // and listing workflows but implementations are free to make arbitrary calls to other - // services or databases, or - // perform simple computations such as this one. - (ctx, details, client, input) -> new NexusService.EchoOutput(input.getMessage())); + // OperationHandler.sync is a meant for exposing simple RPC handlers. + return OperationHandler.sync( + // The method is for making arbitrary short calls to other services or databases, or + // perform simple computations such as this one. Users can also access a workflow client by + // calling + // Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as + // signaling, querying, or listing workflows. + (ctx, details, input) -> new NexusService.EchoOutput(input.getMessage())); } @OperationImpl public OperationHandler hello() { - // Use the WorkflowClientOperationHandlers.fromWorkflowMethod constructor, which is the easiest + // Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest // way to expose a workflow as an operation. - return WorkflowClientOperationHandlers.fromWorkflowMethod( - (ctx, details, client, input) -> - client.newWorkflowStub( - HelloHandlerWorkflow.class, - // Workflow IDs should typically be business meaningful IDs and are used to - // dedupe workflow starts. - // For this example, we're using the request ID allocated by Temporal when the - // caller workflow schedules - // the operation, this ID is guaranteed to be stable across retries of this - // operation. - // - // Task queue defaults to the task queue this operation is handled on. - WorkflowOptions.newBuilder().setWorkflowId(details.getRequestId()).build()) + return WorkflowRunOperation.fromWorkflowMethod( + (ctx, details, input) -> + Nexus.getOperationContext() + .getWorkflowClient() + .newWorkflowStub( + HelloHandlerWorkflow.class, + // Workflow IDs should typically be business meaningful IDs and are used to + // dedupe workflow starts. + // For this example, we're using the request ID allocated by Temporal when + // the + // caller workflow schedules + // the operation, this ID is guaranteed to be stable across retries of this + // operation. + // + // Task queue defaults to the task queue this operation is handled on. + WorkflowOptions.newBuilder().setWorkflowId(details.getRequestId()).build()) ::hello); } } From f51ee952cd184690b9416aa83c7a4b486b88bb40 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 26 Feb 2025 13:48:41 -0800 Subject: [PATCH 208/240] Fix typo (#717) --- core/src/main/java/io/temporal/samples/nexus/README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/io/temporal/samples/nexus/README.MD b/core/src/main/java/io/temporal/samples/nexus/README.MD index 9e848c6d8..dc627f27e 100644 --- a/core/src/main/java/io/temporal/samples/nexus/README.MD +++ b/core/src/main/java/io/temporal/samples/nexus/README.MD @@ -24,7 +24,7 @@ This sample shows how to use Temporal for authoring a Nexus service and call it site](https://learn.temporal.io/getting_started/go/dev_environment/#set-up-a-local-temporal-service-for-development-with-temporal-cli) to install Temporal CLI. -> NOTE: he recommended version is at least v1.3.0. +> NOTE: The recommended version is at least v1.3.0. ### Spin up environment From c6a092ef4430a2a070b98f94eae0aa946483f47c Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Thu, 27 Feb 2025 13:58:51 -0800 Subject: [PATCH 209/240] Add Nexus cancellation sample (#718) * Update Nexus Sample for v1.28.0 * fix typo * Small updates * Add Nexus Cancellation Sample * Update cancellation sample * fix typo * run license check * add log * run spotless --- .../samples/nexuscancellation/README.MD | 36 +++++++ .../caller/CallerStarter.java | 46 +++++++++ .../caller/CallerWorker.java | 51 ++++++++++ .../caller/HelloCallerWorkflow.java | 29 ++++++ .../caller/HelloCallerWorkflowImpl.java | 95 +++++++++++++++++++ .../handler/HandlerWorker.java | 42 ++++++++ .../handler/HelloHandlerWorkflowImpl.java | 48 ++++++++++ 7 files changed, 347 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/nexuscancellation/README.MD create mode 100644 core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD b/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD new file mode 100644 index 000000000..cf39c85c4 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD @@ -0,0 +1,36 @@ +# Nexus Cancellation + +This sample shows how to cancel a Nexus operation from a caller workflow. + +From more details on Nexus and how to setup to run this samples please see the [Nexus Sample](../nexus/README.MD). + +In separate terminal windows: + +### Nexus handler worker + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexuscancellation.handler.HandlerWorker \ + --args="-target-host localhost:7233 -namespace my-target-namespace" +``` + +### Nexus caller worker + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexuscancellation.caller.CallerWorker \ + --args="-target-host localhost:7233 -namespace my-caller-namespace" +``` + +### Start caller workflow + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexuscancellation.caller.CallerStarter \ + --args="-target-host localhost:7233 -namespace my-caller-namespace" +``` + +### Output + +which should result in: +``` +INFO i.t.s.n.caller.CallerStarter - Started workflow workflowId: 326732dd-a2b1-4de7-9ddd-dcee4f9f0229 runId: d580499f-79d5-461d-bd49-6248b4e522ae +INFO i.t.s.n.caller.CallerStarter - Workflow result: Hallo Nexus πŸ‘‹ +``` diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java new file mode 100644 index 000000000..1ee705b1a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscancellation.caller; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.nexus.options.ClientOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CallerStarter { + private static final Logger logger = LoggerFactory.getLogger(CallerStarter.class); + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(CallerWorker.DEFAULT_TASK_QUEUE_NAME).build(); + HelloCallerWorkflow helloWorkflow = + client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); + WorkflowExecution execution = WorkflowClient.start(helloWorkflow::hello, "Nexus"); + logger.info( + "Started workflow workflowId: {} runId: {}", + execution.getWorkflowId(), + execution.getRunId()); + logger.info("Workflow result: {}", helloWorkflow.hello("Nexus")); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java new file mode 100644 index 000000000..37f5eaa5f --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscancellation.caller; + +import io.temporal.client.WorkflowClient; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.NexusServiceOptions; +import java.util.Collections; + +public class CallerWorker { + public static final String DEFAULT_TASK_QUEUE_NAME = "my-caller-workflow-task-queue"; + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); + worker.registerWorkflowImplementationTypes( + WorkflowImplementationOptions.newBuilder() + .setNexusServiceOptions( + Collections.singletonMap( + NexusService.class.getSimpleName(), + NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) + .build(), + HelloCallerWorkflowImpl.class); + + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java new file mode 100644 index 000000000..7f77cc68c --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscancellation.caller; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloCallerWorkflow { + @WorkflowMethod + String hello(String message); +} diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java new file mode 100644 index 000000000..bc3666147 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscancellation.caller; + +import static io.temporal.samples.nexus.service.NexusService.Language.*; + +import io.temporal.failure.CanceledFailure; +import io.temporal.failure.NexusOperationFailure; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.*; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; + +public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { + public static final Logger log = Workflow.getLogger(HelloCallerWorkflowImpl.class); + private static final NexusService.Language[] languages = + new NexusService.Language[] {EN, FR, DE, ES, TR}; + NexusService nexusService = + Workflow.newNexusServiceStub( + NexusService.class, + NexusServiceOptions.newBuilder() + .setOperationOptions( + NexusOperationOptions.newBuilder() + .setScheduleToCloseTimeout(Duration.ofSeconds(10)) + .build()) + .build()); + + @Override + public String hello(String message) { + List> results = new ArrayList<>(languages.length); + + /* + * Create our CancellationScope. Within this scope we call the nexus operation asynchronously + * hello method asynchronously for each of our defined languages. + */ + CancellationScope scope = + Workflow.newCancellationScope( + () -> { + for (NexusService.Language language : languages) { + results.add( + Async.function( + nexusService::hello, new NexusService.HelloInput(message, language))); + } + }); + + /* + * Execute all nexus operations within the CancellationScope. Note that this execution is + * non-blocking as the code inside our cancellation scope is also non-blocking. + */ + scope.run(); + + // We use "anyOf" here to wait for one of the nexus operation invocations to return + NexusService.HelloOutput result = Promise.anyOf(results).get(); + + // Trigger cancellation of all uncompleted nexus operations invocations within the cancellation + // scope + scope.cancel(); + // Optionally, wait for all nexus operations to complete + // + // Note: Once the workflow completes any pending cancellation requests are dropped by the + // server. + for (Promise promise : results) { + try { + promise.get(); + } catch (NexusOperationFailure e) { + // If the operation was cancelled, we can ignore the failure + if (e.getCause() instanceof CanceledFailure) { + log.info("Operation was cancelled"); + continue; + } + throw e; + } + } + return result.getMessage(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java new file mode 100644 index 000000000..a70a47abe --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscancellation.handler; + +import io.temporal.client.WorkflowClient; +import io.temporal.samples.nexus.handler.NexusServiceImpl; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class HandlerWorker { + public static final String DEFAULT_TASK_QUEUE_NAME = "my-handler-task-queue"; + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); + worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); + worker.registerNexusServiceImplementation(new NexusServiceImpl()); + + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java new file mode 100644 index 000000000..246c25e93 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscancellation.handler; + +import io.temporal.failure.ApplicationFailure; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { + @Override + public NexusService.HelloOutput hello(NexusService.HelloInput input) { + // Sleep for a random duration to simulate some work + Workflow.sleep(Duration.ofSeconds(Workflow.newRandom().nextInt(5))); + switch (input.getLanguage()) { + case EN: + return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + case FR: + return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + case DE: + return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + case ES: + return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + case TR: + return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + } + throw ApplicationFailure.newFailure( + "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); + } +} From b8537d058ba10c05ecc4035d2727c276bc0b6fca Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 11 Mar 2025 03:03:58 -0700 Subject: [PATCH 210/240] Update to Java SDK v1.28.1 (#724) --- build.gradle | 2 +- .../temporal/samples/nexus/options/ClientOptions.java | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 51b1a80e5..f1731c4fd 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.28.0' + javaSDKVersion = '1.28.1' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java index 7ba699309..36a42ee2c 100644 --- a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java +++ b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java @@ -19,11 +19,9 @@ package io.temporal.samples.nexus.options; -import io.grpc.Metadata; import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.grpc.stub.MetadataUtils; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.serviceclient.WorkflowServiceStubs; @@ -137,14 +135,6 @@ public static WorkflowClient getWorkflowClient(String[] args) { if (!apiKey.isEmpty()) { serviceStubOptionsBuilder.setEnableHttps(true); serviceStubOptionsBuilder.addApiKey(() -> apiKey); - Metadata.Key TEMPORAL_NAMESPACE_HEADER_KEY = - Metadata.Key.of("temporal-namespace", Metadata.ASCII_STRING_MARSHALLER); - Metadata metadata = new Metadata(); - metadata.put(TEMPORAL_NAMESPACE_HEADER_KEY, namespace); - serviceStubOptionsBuilder.setChannelInitializer( - (channel) -> { - channel.intercept(MetadataUtils.newAttachHeadersInterceptor(metadata)); - }); } WorkflowServiceStubs service = From 46e0a6abe2a8afa2f723e2abfc7a1ac8291b0654 Mon Sep 17 00:00:00 2001 From: HCaupert Date: Fri, 14 Mar 2025 16:09:08 +0100 Subject: [PATCH 211/240] test: added a junit 5 test on SleepForDays (#721) --- .../sleepfordays/SleepForDaysJUnit5Test.java | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysJUnit5Test.java diff --git a/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysJUnit5Test.java b/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysJUnit5Test.java new file mode 100644 index 000000000..44e1f9e68 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysJUnit5Test.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.sleepfordays; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +import io.temporal.client.WorkflowClient; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import java.time.Duration; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class SleepForDaysJUnit5Test { + + @RegisterExtension + public TestWorkflowExtension testWorkflowRule = + TestWorkflowExtension.newBuilder() + .registerWorkflowImplementationTypes(SleepForDaysImpl.class) + .setDoNotStart(true) + .build(); + + @Test + @Timeout(8) + public void testSleepForDays( + TestWorkflowEnvironment testEnv, Worker worker, SleepForDaysWorkflow workflow) { + // Mock activity + SendEmailActivity activities = mock(SendEmailActivity.class); + worker.registerActivitiesImplementations(activities); + // Start environment + testEnv.start(); + + // Start workflow + WorkflowClient.start(workflow::sleepForDays); + + long startTime = testEnv.currentTimeMillis(); + // Time-skip 5 minutes. + testEnv.sleep(Duration.ofMinutes(5)); + // Check that the activity has been called, we're now waiting for the sleep to finish. + verify(activities, times(1)).sendEmail(anyString()); + // Time-skip 3 days. + testEnv.sleep(Duration.ofDays(90)); + // Expect 3 more activity calls. + verify(activities, times(4)).sendEmail(anyString()); + // Send the signal to complete the workflow. + workflow.complete(); + // Expect no more activity calls to have been made - workflow is complete. + workflow.sleepForDays(); + verify(activities, times(4)).sendEmail(anyString()); + // Expect more than 90 days to have passed. + long endTime = testEnv.currentTimeMillis(); + assertEquals(true, endTime - startTime > Duration.ofDays(90).toMillis()); + } +} From d6629abea599c3b78085ff508eb8a2afe3d7188c Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Fri, 14 Mar 2025 15:23:28 -0700 Subject: [PATCH 212/240] Add interceptor to propagate headers to Nexus operations (#719) Add interceptor to propagate headers to Nexus operations --- README.md | 8 ++ .../samples/nexus/options/ClientOptions.java | 9 +- .../samples/nexuscontextpropagation/README.MD | 45 ++++++ .../caller/CallerStarter.java | 64 +++++++++ .../caller/CallerWorker.java | 58 ++++++++ .../caller/EchoCallerWorkflowImpl.java | 46 +++++++ .../caller/HelloCallerWorkflowImpl.java | 53 +++++++ .../handler/HandlerWorker.java | 55 ++++++++ .../handler/HelloHandlerWorkflowImpl.java | 54 ++++++++ .../handler/NexusServiceImpl.java | 81 +++++++++++ .../propogation/MDCContextPropagator.java | 80 +++++++++++ .../NexusMDCContextInterceptor.java | 129 ++++++++++++++++++ 12 files changed, 680 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/MDCContextPropagator.java create mode 100644 core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/NexusMDCContextInterceptor.java diff --git a/README.md b/README.md index b30743697..d3808da94 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,14 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**AWS Encryption SDK**](/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk): Demonstrates how to use the AWS Encryption SDK to encrypt and decrypt payloads with AWS KMS. +#### Nexus Samples + +- [**Getting Started**](/core/src/main/java/io/temporal/samples/nexus): Demonstrates how to get started with Temporal and Nexus. + +- [**Cancellation**](/core/src/main/java/io/temporal/samples/nexuscancellation): Demonstrates how to cancel an async Nexus operation. + +- [**Context/Header Propagation**](/core/src/main/java/io/temporal/samples/nexuscontextpropagation): Demonstrates how to propagate context through Nexus operation headers. + ### Running SpringBoot Samples diff --git a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java index 36a42ee2c..812eb4949 100644 --- a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java +++ b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java @@ -32,7 +32,13 @@ import org.apache.commons.cli.*; public class ClientOptions { + public static WorkflowClient getWorkflowClient(String[] args) { + return getWorkflowClient(args, WorkflowClientOptions.newBuilder()); + } + + public static WorkflowClient getWorkflowClient( + String[] args, WorkflowClientOptions.Builder clientOptions) { Options options = new Options(); Option targetHostOption = new Option("target-host", true, "Host:port for the Temporal service"); targetHostOption.setRequired(false); @@ -139,7 +145,6 @@ public static WorkflowClient getWorkflowClient(String[] args) { WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(serviceStubOptionsBuilder.build()); - return WorkflowClient.newInstance( - service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build()); + return WorkflowClient.newInstance(service, clientOptions.setNamespace(namespace).build()); } } diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD new file mode 100644 index 000000000..1f1800a3a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD @@ -0,0 +1,45 @@ +# Nexus Context Propagation + +This sample shows how to propagate MDC context values from Workflows to Nexus operations. +Nexus does not support `ContextPropagator` since the header format is not compatible. Users should look at `NexusMDCContextInterceptor` for propagating MDC context values. + +From more details on Nexus and how to setup to run this samples please see the [Nexus Sample](../nexus/README.MD). + +In separate terminal windows: + +### Nexus handler worker + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexuscontextpropagation.handler.HandlerWorker \ + --args="-target-host localhost:7233 -namespace my-target-namespace" +``` + +### Nexus caller worker + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexuscontextpropagation.caller.CallerWorker \ + --args="-target-host localhost:7233 -namespace my-caller-namespace" +``` + +### Start caller workflow + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexuscontextpropagation.caller.CallerStarter \ + --args="-target-host localhost:7233 -namespace my-caller-namespace" +``` + +### Output + +which should result in this on the caller side: +``` +INFO i.t.s.n.caller.CallerStarter - Started EchoCallerWorkflow workflowId: 7ac97cb9-b457-4052-af94-d82478c35c5e runId: 01954eb9-6963-7b52-9a1d-b74e64643846 +INFO i.t.s.n.caller.CallerStarter - Workflow result: Nexus Echo πŸ‘‹ +INFO i.t.s.n.caller.CallerStarter - Started HelloCallerWorkflow workflowId: 9e0bc89c-5709-4742-b7c0-868464c2fccf runId: 01954eb9-6ae3-7d6d-b355-71545688309d +INFO i.t.s.n.caller.CallerStarter - Workflow result: Hello Nexus πŸ‘‹ +``` + +And this on the handler side: +``` +INFO i.t.s.n.handler.NexusServiceImpl - Echo called from a workflow with ID : 7ac97cb9-b457-4052-af94-d82478c35c5e +INFO i.t.s.n.h.HelloHandlerWorkflowImpl - HelloHandlerWorkflow called from a workflow with ID : 9e0bc89c-5709-4742-b7c0-868464c2fccf +``` diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java new file mode 100644 index 000000000..823c3ccea --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.caller; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.nexus.caller.EchoCallerWorkflow; +import io.temporal.samples.nexus.caller.HelloCallerWorkflow; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexuscontextpropagation.propogation.MDCContextPropagator; +import java.util.Collections; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CallerStarter { + private static final Logger logger = LoggerFactory.getLogger(CallerStarter.class); + + public static void main(String[] args) { + WorkflowClient client = + ClientOptions.getWorkflowClient( + args, + WorkflowClientOptions.newBuilder() + .setContextPropagators(Collections.singletonList(new MDCContextPropagator()))); + + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(CallerWorker.DEFAULT_TASK_QUEUE_NAME).build(); + EchoCallerWorkflow echoWorkflow = + client.newWorkflowStub(EchoCallerWorkflow.class, workflowOptions); + WorkflowExecution execution = WorkflowClient.start(echoWorkflow::echo, "Nexus Echo πŸ‘‹"); + logger.info( + "Started EchoCallerWorkflow workflowId: {} runId: {}", + execution.getWorkflowId(), + execution.getRunId()); + logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); + HelloCallerWorkflow helloWorkflow = + client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); + logger.info( + "Started HelloCallerWorkflow workflowId: {} runId: {}", + execution.getWorkflowId(), + execution.getRunId()); + logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java new file mode 100644 index 000000000..387ea01be --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.caller; + +import io.temporal.client.WorkflowClient; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.samples.nexuscontextpropagation.propogation.NexusMDCContextInterceptor; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.NexusServiceOptions; +import java.util.Collections; + +public class CallerWorker { + public static final String DEFAULT_TASK_QUEUE_NAME = "my-caller-workflow-task-queue"; + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkerFactory factory = + WorkerFactory.newInstance( + client, + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors(new NexusMDCContextInterceptor()) + .build()); + + Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); + worker.registerWorkflowImplementationTypes( + WorkflowImplementationOptions.newBuilder() + .setNexusServiceOptions( + Collections.singletonMap( + "NexusService", + NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) + .build(), + EchoCallerWorkflowImpl.class, + HelloCallerWorkflowImpl.class); + + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java new file mode 100644 index 000000000..23cb2ce49 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.caller; + +import io.temporal.samples.nexus.caller.EchoCallerWorkflow; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.NexusOperationOptions; +import io.temporal.workflow.NexusServiceOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import org.slf4j.MDC; + +public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { + NexusService nexusService = + Workflow.newNexusServiceStub( + NexusService.class, + NexusServiceOptions.newBuilder() + .setOperationOptions( + NexusOperationOptions.newBuilder() + .setScheduleToCloseTimeout(Duration.ofSeconds(10)) + .build()) + .build()); + + @Override + public String echo(String message) { + MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId()); + return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java new file mode 100644 index 000000000..0fec8c7d4 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.caller; + +import io.temporal.samples.nexus.caller.HelloCallerWorkflow; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.NexusOperationHandle; +import io.temporal.workflow.NexusOperationOptions; +import io.temporal.workflow.NexusServiceOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import org.slf4j.MDC; + +public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { + NexusService nexusService = + Workflow.newNexusServiceStub( + NexusService.class, + NexusServiceOptions.newBuilder() + .setOperationOptions( + NexusOperationOptions.newBuilder() + .setScheduleToCloseTimeout(Duration.ofSeconds(10)) + .build()) + .build()); + + @Override + public String hello(String message, NexusService.Language language) { + MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId()); + NexusOperationHandle handle = + Workflow.startNexusOperation( + nexusService::hello, new NexusService.HelloInput(message, language)); + // Optionally wait for the operation to be started. NexusOperationExecution will contain the + // operation token in case this operation is asynchronous. + handle.getExecution().get(); + return handle.getResult().get().getMessage(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java new file mode 100644 index 000000000..d2536bc41 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.handler; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.samples.nexuscontextpropagation.propogation.MDCContextPropagator; +import io.temporal.samples.nexuscontextpropagation.propogation.NexusMDCContextInterceptor; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerFactoryOptions; +import java.util.Collections; + +public class HandlerWorker { + public static final String DEFAULT_TASK_QUEUE_NAME = "my-handler-task-queue"; + + public static void main(String[] args) { + WorkflowClient client = + ClientOptions.getWorkflowClient( + args, + WorkflowClientOptions.newBuilder() + .setContextPropagators(Collections.singletonList(new MDCContextPropagator()))); + + WorkerFactory factory = + WorkerFactory.newInstance( + client, + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors(new NexusMDCContextInterceptor()) + .build()); + + Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); + worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); + worker.registerNexusServiceImplementation(new NexusServiceImpl()); + + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java new file mode 100644 index 000000000..389368b50 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.handler; + +import io.temporal.failure.ApplicationFailure; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.Workflow; +import org.slf4j.Logger; +import org.slf4j.MDC; + +public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { + public static final Logger log = Workflow.getLogger(HelloHandlerWorkflowImpl.class); + + @Override + public NexusService.HelloOutput hello(NexusService.HelloInput input) { + if (MDC.get("x-nexus-caller-workflow-id") != null) { + log.info( + "HelloHandlerWorkflow called from a workflow with ID : {}", + MDC.get("x-nexus-caller-workflow-id")); + } + switch (input.getLanguage()) { + case EN: + return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + case FR: + return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + case DE: + return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + case ES: + return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + case TR: + return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + } + throw ApplicationFailure.newFailure( + "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java new file mode 100644 index 000000000..cad37b9ed --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.handler; + +import io.nexusrpc.handler.OperationHandler; +import io.nexusrpc.handler.OperationImpl; +import io.nexusrpc.handler.ServiceImpl; +import io.temporal.client.WorkflowOptions; +import io.temporal.nexus.Nexus; +import io.temporal.nexus.WorkflowRunOperation; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; +import io.temporal.samples.nexus.service.NexusService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +// To create a service implementation, annotate the class with @ServiceImpl and provide the +// interface that the service implements. The service implementation class should have methods that +// return OperationHandler that correspond to the operations defined in the service interface. +@ServiceImpl(service = NexusService.class) +public class NexusServiceImpl { + private static final Logger logger = LoggerFactory.getLogger(NexusServiceImpl.class); + + @OperationImpl + public OperationHandler echo() { + // OperationHandler.sync is a meant for exposing simple RPC handlers. + return OperationHandler.sync( + // The method is for making arbitrary short calls to other services or databases, or + // perform simple computations such as this one. Users can also access a workflow client by + // calling + // Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as + // signaling, querying, or listing workflows. + (ctx, details, input) -> { + if (MDC.get("x-nexus-caller-workflow-id") != null) { + logger.info( + "Echo called from a workflow with ID : {}", MDC.get("x-nexus-caller-workflow-id")); + } + return new NexusService.EchoOutput(input.getMessage()); + }); + } + + @OperationImpl + public OperationHandler hello() { + // Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest + // way to expose a workflow as an operation. + return WorkflowRunOperation.fromWorkflowMethod( + (ctx, details, input) -> + Nexus.getOperationContext() + .getWorkflowClient() + .newWorkflowStub( + HelloHandlerWorkflow.class, + // Workflow IDs should typically be business meaningful IDs and are used to + // dedupe workflow starts. + // For this example, we're using the request ID allocated by Temporal when + // the + // caller workflow schedules + // the operation, this ID is guaranteed to be stable across retries of this + // operation. + // + // Task queue defaults to the task queue this operation is handled on. + WorkflowOptions.newBuilder().setWorkflowId(details.getRequestId()).build()) + ::hello); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/MDCContextPropagator.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/MDCContextPropagator.java new file mode 100644 index 000000000..db75395fd --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/MDCContextPropagator.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.propogation; + +import io.temporal.api.common.v1.Payload; +import io.temporal.common.context.ContextPropagator; +import io.temporal.common.converter.DataConverter; +import java.util.HashMap; +import java.util.Map; +import org.slf4j.MDC; + +public class MDCContextPropagator implements ContextPropagator { + + @Override + public String getName() { + return this.getClass().getName(); + } + + @Override + public Object getCurrentContext() { + Map context = new HashMap<>(); + if (MDC.getCopyOfContextMap() == null) { + return context; + } + for (Map.Entry entry : MDC.getCopyOfContextMap().entrySet()) { + if (entry.getKey().startsWith("x-nexus-")) { + context.put(entry.getKey(), entry.getValue()); + } + } + return context; + } + + @Override + public void setCurrentContext(Object context) { + Map contextMap = (Map) context; + for (Map.Entry entry : contextMap.entrySet()) { + MDC.put(entry.getKey(), entry.getValue()); + } + } + + @Override + public Map serializeContext(Object context) { + Map contextMap = (Map) context; + Map serializedContext = new HashMap<>(); + for (Map.Entry entry : contextMap.entrySet()) { + serializedContext.put( + entry.getKey(), DataConverter.getDefaultInstance().toPayload(entry.getValue()).get()); + } + return serializedContext; + } + + @Override + public Object deserializeContext(Map context) { + Map contextMap = new HashMap<>(); + for (Map.Entry entry : context.entrySet()) { + contextMap.put( + entry.getKey(), + DataConverter.getDefaultInstance() + .fromPayload(entry.getValue(), String.class, String.class)); + } + return contextMap; + } +} diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/NexusMDCContextInterceptor.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/NexusMDCContextInterceptor.java new file mode 100644 index 000000000..944767e4b --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/NexusMDCContextInterceptor.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.nexuscontextpropagation.propogation; + +import io.nexusrpc.OperationException; +import io.nexusrpc.handler.OperationContext; +import io.temporal.common.interceptors.NexusOperationInboundCallsInterceptor; +import io.temporal.common.interceptors.WorkerInterceptorBase; +import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; +import java.util.Map; +import org.slf4j.MDC; + +/** + * Propagates MDC context from the caller workflow to the Nexus service through the operation + * headers. + */ +public class NexusMDCContextInterceptor extends WorkerInterceptorBase { + private static final String NEXUS_HEADER_PREFIX = "x-nexus-"; + + @Override + public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) { + return new WorkflowInboundCallsInterceptorNexusMDC(next); + } + + public static class WorkflowInboundCallsInterceptorNexusMDC + extends io.temporal.common.interceptors.WorkflowInboundCallsInterceptorBase { + private final WorkflowInboundCallsInterceptor next; + + public WorkflowInboundCallsInterceptorNexusMDC(WorkflowInboundCallsInterceptor next) { + super(next); + this.next = next; + } + + @Override + public void init(WorkflowOutboundCallsInterceptor outboundCalls) { + next.init(new WorkflowOutboundCallsInterceptorNexusMDC(outboundCalls)); + } + } + + public static class WorkflowOutboundCallsInterceptorNexusMDC + extends io.temporal.common.interceptors.WorkflowOutboundCallsInterceptorBase { + private final WorkflowOutboundCallsInterceptor next; + + public WorkflowOutboundCallsInterceptorNexusMDC(WorkflowOutboundCallsInterceptor next) { + super(next); + this.next = next; + } + + @Override + public ExecuteNexusOperationOutput executeNexusOperation( + ExecuteNexusOperationInput input) { + Map contextMap = MDC.getCopyOfContextMap(); + if (contextMap != null) { + Map headerMap = input.getHeaders(); + contextMap.forEach( + (k, v) -> { + if (k.startsWith(NEXUS_HEADER_PREFIX)) { + headerMap.put(k, v); + } + }); + } + return next.executeNexusOperation(input); + } + } + + @Override + public NexusOperationInboundCallsInterceptor interceptNexusOperation( + OperationContext context, NexusOperationInboundCallsInterceptor next) { + return new NexusOperationInboundCallsInterceptorNexusMDC(next); + } + + private static class NexusOperationInboundCallsInterceptorNexusMDC + extends io.temporal.common.interceptors.NexusOperationInboundCallsInterceptorBase { + private final NexusOperationInboundCallsInterceptor next; + + public NexusOperationInboundCallsInterceptorNexusMDC( + NexusOperationInboundCallsInterceptor next) { + super(next); + this.next = next; + } + + @Override + public StartOperationOutput startOperation(StartOperationInput input) + throws OperationException { + input + .getOperationContext() + .getHeaders() + .forEach( + (k, v) -> { + if (k.startsWith(NEXUS_HEADER_PREFIX)) { + MDC.put(k, v); + } + }); + return next.startOperation(input); + } + + @Override + public CancelOperationOutput cancelOperation(CancelOperationInput input) { + input + .getOperationContext() + .getHeaders() + .forEach( + (k, v) -> { + if (k.startsWith(NEXUS_HEADER_PREFIX)) { + MDC.put(k, v); + } + }); + return next.cancelOperation(input); + } + } +} From 42086f61a9a058663ee6e3ee0ae8fae983a98539 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Wed, 26 Mar 2025 08:52:38 -0400 Subject: [PATCH 213/240] Fix directory name (#728) --- .../samples/nexuscontextpropagation/caller/CallerStarter.java | 2 +- .../samples/nexuscontextpropagation/caller/CallerWorker.java | 2 +- .../nexuscontextpropagation/handler/HandlerWorker.java | 4 ++-- .../{propogation => propagation}/MDCContextPropagator.java | 2 +- .../NexusMDCContextInterceptor.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename core/src/main/java/io/temporal/samples/nexuscontextpropagation/{propogation => propagation}/MDCContextPropagator.java (97%) rename core/src/main/java/io/temporal/samples/nexuscontextpropagation/{propogation => propagation}/NexusMDCContextInterceptor.java (98%) diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java index 823c3ccea..9a765c9c3 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java @@ -27,7 +27,7 @@ import io.temporal.samples.nexus.caller.HelloCallerWorkflow; import io.temporal.samples.nexus.options.ClientOptions; import io.temporal.samples.nexus.service.NexusService; -import io.temporal.samples.nexuscontextpropagation.propogation.MDCContextPropagator; +import io.temporal.samples.nexuscontextpropagation.propagation.MDCContextPropagator; import java.util.Collections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java index 387ea01be..86fc0b064 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java @@ -21,7 +21,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexuscontextpropagation.propogation.NexusMDCContextInterceptor; +import io.temporal.samples.nexuscontextpropagation.propagation.NexusMDCContextInterceptor; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerFactoryOptions; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java index d2536bc41..e476924e1 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java @@ -22,8 +22,8 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexuscontextpropagation.propogation.MDCContextPropagator; -import io.temporal.samples.nexuscontextpropagation.propogation.NexusMDCContextInterceptor; +import io.temporal.samples.nexuscontextpropagation.propagation.MDCContextPropagator; +import io.temporal.samples.nexuscontextpropagation.propagation.NexusMDCContextInterceptor; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerFactoryOptions; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/MDCContextPropagator.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/MDCContextPropagator.java similarity index 97% rename from core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/MDCContextPropagator.java rename to core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/MDCContextPropagator.java index db75395fd..a8b65be2f 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/MDCContextPropagator.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/MDCContextPropagator.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.nexuscontextpropagation.propogation; +package io.temporal.samples.nexuscontextpropagation.propagation; import io.temporal.api.common.v1.Payload; import io.temporal.common.context.ContextPropagator; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/NexusMDCContextInterceptor.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/NexusMDCContextInterceptor.java similarity index 98% rename from core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/NexusMDCContextInterceptor.java rename to core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/NexusMDCContextInterceptor.java index 944767e4b..f2fa07f23 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propogation/NexusMDCContextInterceptor.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/NexusMDCContextInterceptor.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.samples.nexuscontextpropagation.propogation; +package io.temporal.samples.nexuscontextpropagation.propagation; import io.nexusrpc.OperationException; import io.nexusrpc.handler.OperationContext; From 7e00384d75bcd6640e3eac1dcc763e0327836d36 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Wed, 26 Mar 2025 17:49:03 -0400 Subject: [PATCH 214/240] Nexus sample README edits (#729) --- .../java/io/temporal/samples/nexuscancellation/README.MD | 4 ++-- .../io/temporal/samples/nexuscontextpropagation/README.MD | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD b/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD index cf39c85c4..f4da82852 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD @@ -2,9 +2,9 @@ This sample shows how to cancel a Nexus operation from a caller workflow. -From more details on Nexus and how to setup to run this samples please see the [Nexus Sample](../nexus/README.MD). +To run this sample, set up your environment following the instructions in the main [Nexus Sample](../nexus/README.md). -In separate terminal windows: +Next, in separate terminal windows: ### Nexus handler worker diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD index 1f1800a3a..79453cc4d 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD @@ -1,11 +1,11 @@ # Nexus Context Propagation -This sample shows how to propagate MDC context values from Workflows to Nexus operations. +This sample shows how to propagate MDC (Mapped Diagnostic Context) context values from Workflows to Nexus operations. Nexus does not support `ContextPropagator` since the header format is not compatible. Users should look at `NexusMDCContextInterceptor` for propagating MDC context values. -From more details on Nexus and how to setup to run this samples please see the [Nexus Sample](../nexus/README.MD). +To run this sample, set up your environment following the instructions in the main [Nexus Sample](../nexus/README.md). -In separate terminal windows: +Next, in separate terminal windows: ### Nexus handler worker From 350f4c2e829fd2205f08ffd0e1ba13a79fc47af8 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 30 Apr 2025 11:55:22 -0700 Subject: [PATCH 215/240] Call out WorkflowRunOperation.fromWorkflowHandler (#735) --- .../io/temporal/samples/nexus/handler/NexusServiceImpl.java | 5 ++++- .../nexuscontextpropagation/handler/NexusServiceImpl.java | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java index d7fda2fd9..e4a58ae95 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java @@ -47,7 +47,10 @@ public OperationHandler echo() @OperationImpl public OperationHandler hello() { // Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest - // way to expose a workflow as an operation. + // way to expose a workflow as an operation. To expose a workflow with a different input + // parameters then the operation or from an untyped stub, use the + // WorkflowRunOperation.fromWorkflowHandler constructor and the appropriate constructor method + // on WorkflowHandle. return WorkflowRunOperation.fromWorkflowMethod( (ctx, details, input) -> Nexus.getOperationContext() diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java index cad37b9ed..b4ac16493 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java @@ -59,7 +59,10 @@ public OperationHandler echo() @OperationImpl public OperationHandler hello() { // Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest - // way to expose a workflow as an operation. + // way to expose a workflow as an operation. To expose a workflow with a different input + // parameters then the operation or from an untyped stub, use the + // WorkflowRunOperation.fromWorkflowHandler constructor and the appropriate constructor method + // on WorkflowHandle. return WorkflowRunOperation.fromWorkflowMethod( (ctx, details, input) -> Nexus.getOperationContext() From fd5bd1f1d53ff8bd8079fab0971dde1e9a1bcbdc Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 5 May 2025 08:27:33 -0700 Subject: [PATCH 216/240] Remove license per file (#737) Remove license per file --- .github/workflows/ci.yml | 6 +++--- LICENSE.txt => LICENSE | 2 +- build.gradle | 11 ----------- .../samples/asyncchild/ChildWorkflow.java | 19 ------------------- .../samples/asyncchild/ChildWorkflowImpl.java | 19 ------------------- .../samples/asyncchild/ParentWorkflow.java | 19 ------------------- .../asyncchild/ParentWorkflowImpl.java | 19 ------------------- .../temporal/samples/asyncchild/Starter.java | 19 ------------------- .../asyncuntypedchild/ChildWorkflow.java | 19 ------------------- .../asyncuntypedchild/ChildWorkflowImpl.java | 19 ------------------- .../asyncuntypedchild/ParentWorkflow.java | 19 ------------------- .../asyncuntypedchild/ParentWorkflowImpl.java | 19 ------------------- .../samples/asyncuntypedchild/Starter.java | 19 ------------------- .../HeartbeatingActivityBatchStarter.java | 19 ------------------- .../HeartbeatingActivityBatchWorker.java | 19 ------------------- .../HeartbeatingActivityBatchWorkflow.java | 19 ------------------- ...HeartbeatingActivityBatchWorkflowImpl.java | 19 ------------------- .../heartbeatingactivity/RecordLoader.java | 19 ------------------- .../RecordLoaderImpl.java | 19 ------------------- .../heartbeatingactivity/RecordProcessor.java | 19 ------------------- .../RecordProcessorActivity.java | 19 ------------------- .../RecordProcessorActivityImpl.java | 19 ------------------- .../RecordProcessorImpl.java | 19 ------------------- .../heartbeatingactivity/SingleRecord.java | 19 ------------------- .../batch/iterator/IteratorBatchStarter.java | 19 ------------------- .../batch/iterator/IteratorBatchWorker.java | 19 ------------------- .../batch/iterator/IteratorBatchWorkflow.java | 19 ------------------- .../iterator/IteratorBatchWorkflowImpl.java | 19 ------------------- .../samples/batch/iterator/RecordLoader.java | 19 ------------------- .../batch/iterator/RecordLoaderImpl.java | 19 ------------------- .../iterator/RecordProcessorWorkflow.java | 19 ------------------- .../iterator/RecordProcessorWorkflowImpl.java | 19 ------------------- .../samples/batch/iterator/SingleRecord.java | 19 ------------------- .../batch/slidingwindow/BatchProgress.java | 19 ------------------- .../batch/slidingwindow/BatchWorkflow.java | 19 ------------------- .../slidingwindow/BatchWorkflowImpl.java | 19 ------------------- .../slidingwindow/ProcessBatchInput.java | 19 ------------------- .../batch/slidingwindow/RecordIterable.java | 19 ------------------- .../batch/slidingwindow/RecordLoader.java | 19 ------------------- .../batch/slidingwindow/RecordLoaderImpl.java | 19 ------------------- .../RecordProcessorWorkflow.java | 19 ------------------- .../RecordProcessorWorkflowImpl.java | 19 ------------------- .../batch/slidingwindow/SingleRecord.java | 19 ------------------- .../SlidingWindowBatchStarter.java | 19 ------------------- .../SlidingWindowBatchWorker.java | 19 ------------------- .../SlidingWindowBatchWorkflow.java | 19 ------------------- .../SlidingWindowBatchWorkflowImpl.java | 19 ------------------- .../temporal/samples/bookingsaga/Booking.java | 19 ------------------- .../bookingsaga/TripBookingActivities.java | 19 ------------------- .../TripBookingActivitiesImpl.java | 19 ------------------- .../bookingsaga/TripBookingClient.java | 19 ------------------- .../bookingsaga/TripBookingWorker.java | 19 ------------------- .../bookingsaga/TripBookingWorkflow.java | 19 ------------------- .../bookingsaga/TripBookingWorkflowImpl.java | 19 ------------------- .../samples/bookingsyncsaga/Booking.java | 19 ------------------- .../TripBookingActivities.java | 19 ------------------- .../TripBookingActivitiesImpl.java | 19 ------------------- .../bookingsyncsaga/TripBookingClient.java | 19 ------------------- .../bookingsyncsaga/TripBookingWorker.java | 19 ------------------- .../bookingsyncsaga/TripBookingWorkflow.java | 19 ------------------- .../TripBookingWorkflowImpl.java | 19 ------------------- .../common/QueryWorkflowExecution.java | 19 ------------------- .../countinterceptor/ClientCounter.java | 19 ------------------- .../countinterceptor/InterceptorStarter.java | 19 ------------------- .../SimpleClientCallsInterceptor.java | 19 ------------------- .../SimpleClientInterceptor.java | 19 ------------------- ...eCountActivityInboundCallsInterceptor.java | 19 ------------------- .../SimpleCountWorkerInterceptor.java | 19 ------------------- ...eCountWorkflowInboundCallsInterceptor.java | 19 ------------------- ...CountWorkflowOutboundCallsInterceptor.java | 19 ------------------- .../countinterceptor/WorkerCounter.java | 19 ------------------- .../activities/MyActivities.java | 19 ------------------- .../activities/MyActivitiesImpl.java | 19 ------------------- .../workflow/MyChildWorkflow.java | 19 ------------------- .../workflow/MyChildWorkflowImpl.java | 19 ------------------- .../countinterceptor/workflow/MyWorkflow.java | 19 ------------------- .../workflow/MyWorkflowImpl.java | 19 ------------------- .../CustomChangeVersionActivities.java | 19 ------------------- .../CustomChangeVersionActivitiesImpl.java | 19 ------------------- .../CustomChangeVersionStarter.java | 19 ------------------- .../CustomChangeVersionWorkflow.java | 19 ------------------- .../CustomChangeVersionWorkflowImpl.java | 19 ------------------- .../temporal/samples/dsl/DslActivities.java | 19 ------------------- .../samples/dsl/DslActivitiesImpl.java | 19 ------------------- .../io/temporal/samples/dsl/DslWorkflow.java | 19 ------------------- .../temporal/samples/dsl/DslWorkflowImpl.java | 19 ------------------- .../java/io/temporal/samples/dsl/Starter.java | 19 ------------------- .../io/temporal/samples/dsl/model/Flow.java | 19 ------------------- .../samples/dsl/model/FlowAction.java | 19 ------------------- .../earlyreturn/EarlyReturnClient.java | 19 ------------------- .../earlyreturn/EarlyReturnWorker.java | 19 ------------------- .../samples/earlyreturn/Transaction.java | 19 ------------------- .../earlyreturn/TransactionActivities.java | 19 ------------------- .../TransactionActivitiesImpl.java | 19 ------------------- .../earlyreturn/TransactionRequest.java | 19 ------------------- .../earlyreturn/TransactionWorkflow.java | 19 ------------------- .../earlyreturn/TransactionWorkflowImpl.java | 19 ------------------- .../samples/earlyreturn/TxResult.java | 19 ------------------- .../encodefailures/CustomerAgeCheck.java | 19 ------------------- .../encodefailures/CustomerAgeCheckImpl.java | 19 ------------------- .../InvalidCustomerException.java | 19 ------------------- .../samples/encodefailures/MyCustomer.java | 19 ------------------- .../SimplePrefixPayloadCodec.java | 19 ------------------- .../samples/encodefailures/Starter.java | 19 ------------------- .../samples/encryptedpayloads/CryptCodec.java | 19 ------------------- .../EncryptedPayloadsActivity.java | 19 ------------------- .../RunMyWorkflows.java | 19 ------------------- .../activities/ForInterceptorActivities.java | 19 ------------------- .../ForInterceptorActivitiesImpl.java | 19 ------------------- .../activities/MyActivities.java | 19 ------------------- .../activities/MyActivitiesImpl.java | 19 ------------------- .../MyActivityInboundCallsInterceptor.java | 19 ------------------- .../interceptor/MyWorkerInterceptor.java | 19 ------------------- .../MyWorkflowInboundCallsInterceptor.java | 19 ------------------- .../MyWorkflowOutboundCallsInterceptor.java | 19 ------------------- .../workflows/MyWorkflow.java | 19 ------------------- .../workflows/MyWorkflowOne.java | 19 ------------------- .../workflows/MyWorkflowOneImpl.java | 19 ------------------- .../workflows/MyWorkflowTwo.java | 19 ------------------- .../workflows/MyWorkflowTwoImpl.java | 19 ------------------- .../fileprocessing/FileProcessingStarter.java | 19 ------------------- .../fileprocessing/FileProcessingWorker.java | 19 ------------------- .../FileProcessingWorkflow.java | 19 ------------------- .../FileProcessingWorkflowImpl.java | 19 ------------------- .../fileprocessing/StoreActivities.java | 19 ------------------- .../fileprocessing/StoreActivitiesImpl.java | 19 ------------------- .../samples/getresultsasync/MyWorkflow.java | 19 ------------------- .../getresultsasync/MyWorkflowImpl.java | 19 ------------------- .../samples/getresultsasync/Starter.java | 19 ------------------- .../samples/getresultsasync/Worker.java | 19 ------------------- .../samples/hello/HelloAccumulator.java | 19 ------------------- .../temporal/samples/hello/HelloActivity.java | 19 ------------------- .../hello/HelloActivityExclusiveChoice.java | 19 ------------------- .../samples/hello/HelloActivityRetry.java | 19 ------------------- .../io/temporal/samples/hello/HelloAsync.java | 19 ------------------- .../hello/HelloAsyncActivityCompletion.java | 19 ------------------- .../samples/hello/HelloAsyncLambda.java | 19 ------------------- .../io/temporal/samples/hello/HelloAwait.java | 19 ------------------- .../samples/hello/HelloCancellationScope.java | 19 ------------------- .../HelloCancellationScopeWithTimer.java | 19 ------------------- .../io/temporal/samples/hello/HelloChild.java | 19 ------------------- .../io/temporal/samples/hello/HelloCron.java | 19 ------------------- .../samples/hello/HelloDelayedStart.java | 19 ------------------- .../hello/HelloDetachedCancellationScope.java | 19 ------------------- .../temporal/samples/hello/HelloDynamic.java | 19 ------------------- .../hello/HelloEagerWorkflowStart.java | 19 ------------------- .../samples/hello/HelloException.java | 19 ------------------- .../samples/hello/HelloLocalActivity.java | 19 ------------------- .../samples/hello/HelloParallelActivity.java | 19 ------------------- .../temporal/samples/hello/HelloPeriodic.java | 19 ------------------- .../hello/HelloPolymorphicActivity.java | 19 ------------------- .../io/temporal/samples/hello/HelloQuery.java | 19 ------------------- .../io/temporal/samples/hello/HelloSaga.java | 19 ------------------- .../samples/hello/HelloSchedules.java | 19 ------------------- .../samples/hello/HelloSearchAttributes.java | 19 ------------------- .../samples/hello/HelloSideEffect.java | 19 ------------------- .../temporal/samples/hello/HelloSignal.java | 19 ------------------- .../samples/hello/HelloSignalWithTimer.java | 19 ------------------- .../hello/HelloTypedSearchAttributes.java | 19 ------------------- .../temporal/samples/hello/HelloUpdate.java | 19 ------------------- .../samples/hello/HelloWorkflowTimer.java | 19 ------------------- .../awsencryptionsdk/EncryptedPayloads.java | 19 ------------------- .../awsencryptionsdk/KeyringCodec.java | 19 ------------------- .../samples/listworkflows/Customer.java | 19 ------------------- .../listworkflows/CustomerActivities.java | 19 ------------------- .../listworkflows/CustomerActivitiesImpl.java | 19 ------------------- .../listworkflows/CustomerWorkflow.java | 19 ------------------- .../listworkflows/CustomerWorkflowImpl.java | 19 ------------------- .../samples/listworkflows/Starter.java | 19 ------------------- .../samples/metrics/MetricsStarter.java | 19 ------------------- .../samples/metrics/MetricsUtils.java | 19 ------------------- .../samples/metrics/MetricsWorker.java | 19 ------------------- .../metrics/activities/MetricsActivities.java | 19 ------------------- .../activities/MetricsActivitiesImpl.java | 19 ------------------- .../metrics/workflow/MetricsWorkflow.java | 19 ------------------- .../metrics/workflow/MetricsWorkflowImpl.java | 19 ------------------- .../temporal/samples/moneybatch/Account.java | 19 ------------------- .../moneybatch/AccountActivityWorker.java | 19 ------------------- .../samples/moneybatch/AccountImpl.java | 19 ------------------- .../moneybatch/AccountTransferWorker.java | 19 ------------------- .../moneybatch/AccountTransferWorkflow.java | 19 ------------------- .../AccountTransferWorkflowImpl.java | 19 ------------------- .../samples/moneybatch/TransferRequester.java | 19 ------------------- .../samples/moneytransfer/Account.java | 19 ------------------- .../moneytransfer/AccountActivityWorker.java | 19 ------------------- .../samples/moneytransfer/AccountImpl.java | 19 ------------------- .../moneytransfer/AccountTransferWorker.java | 19 ------------------- .../AccountTransferWorkflow.java | 19 ------------------- .../AccountTransferWorkflowImpl.java | 19 ------------------- .../moneytransfer/TransferRequester.java | 19 ------------------- .../samples/nexus/caller/CallerStarter.java | 19 ------------------- .../samples/nexus/caller/CallerWorker.java | 19 ------------------- .../nexus/caller/EchoCallerWorkflow.java | 19 ------------------- .../nexus/caller/EchoCallerWorkflowImpl.java | 19 ------------------- .../nexus/caller/HelloCallerWorkflow.java | 19 ------------------- .../nexus/caller/HelloCallerWorkflowImpl.java | 19 ------------------- .../samples/nexus/handler/HandlerWorker.java | 19 ------------------- .../nexus/handler/HelloHandlerWorkflow.java | 19 ------------------- .../handler/HelloHandlerWorkflowImpl.java | 19 ------------------- .../nexus/handler/NexusServiceImpl.java | 19 ------------------- .../samples/nexus/options/ClientOptions.java | 19 ------------------- .../samples/nexus/service/NexusService.java | 19 ------------------- .../caller/CallerStarter.java | 19 ------------------- .../caller/CallerWorker.java | 19 ------------------- .../caller/HelloCallerWorkflow.java | 19 ------------------- .../caller/HelloCallerWorkflowImpl.java | 19 ------------------- .../handler/HandlerWorker.java | 19 ------------------- .../handler/HelloHandlerWorkflowImpl.java | 19 ------------------- .../caller/CallerStarter.java | 19 ------------------- .../caller/CallerWorker.java | 19 ------------------- .../caller/EchoCallerWorkflowImpl.java | 19 ------------------- .../caller/HelloCallerWorkflowImpl.java | 19 ------------------- .../handler/HandlerWorker.java | 19 ------------------- .../handler/HelloHandlerWorkflowImpl.java | 19 ------------------- .../handler/NexusServiceImpl.java | 19 ------------------- .../propagation/MDCContextPropagator.java | 19 ------------------- .../NexusMDCContextInterceptor.java | 19 ------------------- .../cloudevents/CEWorkflow.java | 19 ------------------- .../cloudevents/CEWorkflowImpl.java | 19 ------------------- .../CloudEventsPayloadConverter.java | 19 ------------------- .../payloadconverter/cloudevents/Starter.java | 19 ------------------- .../crypto/CryptoWorkflow.java | 19 ------------------- .../crypto/CryptoWorkflowImpl.java | 19 ------------------- .../payloadconverter/crypto/MyCustomer.java | 19 ------------------- .../payloadconverter/crypto/Starter.java | 19 ------------------- .../peractivityoptions/FailingActivities.java | 19 ------------------- .../FailingActivitiesImpl.java | 19 ------------------- .../PerActivityOptionsWorkflow.java | 19 ------------------- .../PerActivityOptionsWorkflowImpl.java | 19 ------------------- .../samples/peractivityoptions/Starter.java | 19 ------------------- .../samples/polling/PollingActivities.java | 19 ------------------- .../samples/polling/PollingWorkflow.java | 19 ------------------- .../temporal/samples/polling/TestService.java | 19 ------------------- .../frequent/FrequentPollingActivityImpl.java | 19 ------------------- .../frequent/FrequentPollingStarter.java | 19 ------------------- .../frequent/FrequentPollingWorkflowImpl.java | 19 ------------------- .../InfrequentPollingActivityImpl.java | 19 ------------------- .../infrequent/InfrequentPollingStarter.java | 19 ------------------- .../InfrequentPollingWorkflowImpl.java | 19 ------------------- ...uentPollingWithRetryAfterActivityImpl.java | 19 ------------------- ...nfrequentPollingWithRetryAfterStarter.java | 19 ------------------- ...uentPollingWithRetryAfterWorkflowImpl.java | 19 ------------------- .../PeriodicPollingActivityImpl.java | 19 ------------------- .../PeriodicPollingChildWorkflowImpl.java | 19 ------------------- .../PeriodicPollingStarter.java | 19 ------------------- .../PeriodicPollingWorkflowImpl.java | 19 ------------------- .../PollingChildWorkflow.java | 19 ------------------- .../FailureRequester.java | 19 ------------------- .../retryonsignalinterceptor/MyActivity.java | 19 ------------------- .../MyActivityImpl.java | 19 ------------------- .../retryonsignalinterceptor/MyWorkflow.java | 19 ------------------- .../MyWorkflowImpl.java | 19 ------------------- .../MyWorkflowWorker.java | 19 ------------------- .../QueryRequester.java | 19 ------------------- .../RetryOnSignalInterceptorListener.java | 19 ------------------- .../RetryOnSignalWorkerInterceptor.java | 19 ------------------- ...SignalWorkflowInboundCallsInterceptor.java | 19 ------------------- ...ignalWorkflowOutboundCallsInterceptor.java | 19 ------------------- .../RetryRequester.java | 19 ------------------- .../ClusterManagerActivities.java | 19 ------------------- .../ClusterManagerActivitiesImpl.java | 19 ------------------- .../ClusterManagerWorkflow.java | 19 ------------------- .../ClusterManagerWorkflowImpl.java | 19 ------------------- .../ClusterManagerWorkflowStarter.java | 19 ------------------- .../ClusterManagerWorkflowWorker.java | 19 ------------------- .../sleepfordays/SendEmailActivity.java | 19 ------------------- .../sleepfordays/SendEmailActivityImpl.java | 19 ------------------- .../sleepfordays/SleepForDaysImpl.java | 19 ------------------- .../sleepfordays/SleepForDaysWorkflow.java | 19 ------------------- .../samples/sleepfordays/Starter.java | 19 ------------------- .../temporal/samples/sleepfordays/Worker.java | 19 ------------------- .../io/temporal/samples/ssl/MyWorkflow.java | 19 ------------------- .../temporal/samples/ssl/MyWorkflowImpl.java | 19 ------------------- .../samples/ssl/SslEnabledWorkerCustomCA.java | 19 ------------------- .../java/io/temporal/samples/ssl/Starter.java | 19 ------------------- .../samples/terminateworkflow/MyWorkflow.java | 19 ------------------- .../terminateworkflow/MyWorkflowImpl.java | 19 ------------------- .../samples/terminateworkflow/Starter.java | 19 ------------------- .../temporal/samples/tracing/JaegerUtils.java | 19 ------------------- .../io/temporal/samples/tracing/Starter.java | 19 ------------------- .../samples/tracing/TracingWorker.java | 19 ------------------- .../tracing/workflow/TracingActivities.java | 19 ------------------- .../workflow/TracingActivitiesImpl.java | 19 ------------------- .../workflow/TracingChildWorkflow.java | 19 ------------------- .../workflow/TracingChildWorkflowImpl.java | 19 ------------------- .../tracing/workflow/TracingWorkflow.java | 19 ------------------- .../tracing/workflow/TracingWorkflowImpl.java | 19 ------------------- .../updatabletimer/DynamicSleepWorkflow.java | 19 ------------------- .../DynamicSleepWorkflowImpl.java | 19 ------------------- .../DynamicSleepWorkflowStarter.java | 19 ------------------- .../DynamicSleepWorkflowWorker.java | 19 ------------------- .../updatabletimer/UpdatableTimer.java | 19 ------------------- .../updatabletimer/WakeUpTimeUpdater.java | 19 ------------------- .../samples/asyncchild/AsyncChildTest.java | 19 ------------------- .../AsyncUntypedChildTest.java | 19 ------------------- ...HeartbeatingActivityBatchWorkflowTest.java | 19 ------------------- .../IteratorIteratorBatchWorkflowTest.java | 19 ------------------- .../SlidingWindowBatchWorkflowTest.java | 19 ------------------- .../bookingsaga/TripBookingWorkflowTest.java | 19 ------------------- .../TripBookingWorkflowTest.java | 19 ------------------- .../ClientCountInterceptorTest.java | 19 ------------------- .../WorkerCountInterceptorTest.java | 19 ------------------- .../temporal/samples/dsl/DslWorkflowTest.java | 19 ------------------- .../earlyreturn/TransactionWorkflowTest.java | 19 ------------------- .../encodefailures/EncodeFailuresTest.java | 19 ------------------- .../ExcludeFromInterceptorTest.java | 19 ------------------- .../fileprocessing/FileProcessingTest.java | 19 ------------------- .../getresultsasync/GetResultsAsyncTest.java | 19 ------------------- .../samples/hello/HelloAccumulatorTest.java | 19 ------------------- ...elloActivityExclusiveChoiceJUnit5Test.java | 19 ------------------- .../HelloActivityExclusiveChoiceTest.java | 19 ------------------- .../hello/HelloActivityJUnit5Test.java | 19 ------------------- .../hello/HelloActivityReplayTest.java | 19 ------------------- .../samples/hello/HelloActivityRetryTest.java | 19 ------------------- .../samples/hello/HelloActivityTest.java | 19 ------------------- .../HelloAsyncActivityCompletionTest.java | 19 ------------------- .../samples/hello/HelloAsyncLambdaTest.java | 19 ------------------- .../samples/hello/HelloAsyncTest.java | 19 ------------------- .../samples/hello/HelloAwaitTest.java | 19 ------------------- .../hello/HelloCancellationScopeTest.java | 19 ------------------- .../HelloCancellationScopeWithTimerTest.java | 19 ------------------- .../samples/hello/HelloChildJUnit5Test.java | 19 ------------------- .../samples/hello/HelloChildTest.java | 19 ------------------- .../temporal/samples/hello/HelloCronTest.java | 19 ------------------- .../samples/hello/HelloDelayedStartTest.java | 19 ------------------- .../HelloDetachedCancellationScopeTest.java | 19 ------------------- .../hello/HelloDynamicActivityJUnit5Test.java | 19 ------------------- .../samples/hello/HelloDynamicTest.java | 19 ------------------- .../hello/HelloEagerWorkflowStartTest.java | 19 ------------------- .../samples/hello/HelloExceptionTest.java | 19 ------------------- .../samples/hello/HelloLocalActivityTest.java | 19 ------------------- .../hello/HelloParallelActivityTest.java | 19 ------------------- .../samples/hello/HelloPeriodicTest.java | 19 ------------------- .../hello/HelloPolymorphicActivityTest.java | 19 ------------------- .../samples/hello/HelloQueryTest.java | 19 ------------------- .../hello/HelloSearchAttributesTest.java | 19 ------------------- .../samples/hello/HelloSideEffectTest.java | 19 ------------------- .../samples/hello/HelloSignalTest.java | 19 ------------------- .../hello/HelloSignalWithTimerTest.java | 19 ------------------- .../samples/hello/HelloUpdateTest.java | 19 ------------------- .../samples/hello/HelloWorkflowTimerTest.java | 19 ------------------- .../listworkflows/ListWorkflowsTest.java | 19 ------------------- .../temporal/samples/metrics/MetricsTest.java | 19 ------------------- .../moneybatch/TransferWorkflowTest.java | 19 ------------------- .../moneytransfer/TransferWorkflowTest.java | 19 ------------------- .../nexus/caller/CallerWorkflowTest.java | 19 ------------------- .../CloudEventsPayloadConverterTest.java | 19 ------------------- .../CryptoPayloadConverterTest.java | 19 ------------------- .../PerActivityOptionsTest.java | 19 ------------------- .../samples/polling/FrequentPollingTest.java | 19 ------------------- .../polling/InfrequentPollingTest.java | 19 ------------------- .../samples/polling/PeriodicPollingTest.java | 19 ------------------- .../RetryOnSignalInterceptorTest.java | 19 ------------------- .../ClusterManagerWorkflowWorkerTest.java | 19 ------------------- .../sleepfordays/SleepForDaysJUnit5Test.java | 19 ------------------- .../sleepfordays/SleepForDaysTest.java | 19 ------------------- .../TerminateWorkflowTest.java | 19 ------------------- .../temporal/samples/tracing/TracingTest.java | 19 ------------------- license-header.txt | 16 ---------------- .../samples/springboot/SamplesController.java | 19 ------------------- .../TemporalSpringbootSamplesApplication.java | 19 ------------------- .../springboot/hello/HelloActivity.java | 19 ------------------- .../springboot/hello/HelloActivityImpl.java | 19 ------------------- .../springboot/hello/HelloWorkflow.java | 19 ------------------- .../springboot/hello/HelloWorkflowImpl.java | 19 ------------------- .../springboot/hello/model/Person.java | 19 ------------------- .../samples/springboot/HelloSampleTest.java | 19 ------------------- .../samples/springboot/SamplesController.java | 19 ------------------- .../TemporalSpringbootSamplesApplication.java | 19 ------------------- .../actuator/WorkerActuatorEndpoint.java | 19 ------------------- .../samples/springboot/camel/CamelConfig.java | 19 ------------------- .../springboot/camel/CamelResource.java | 19 ------------------- .../samples/springboot/camel/CamelRoutes.java | 19 ------------------- .../samples/springboot/camel/OfficeOrder.java | 19 ------------------- .../springboot/camel/OrderActivity.java | 19 ------------------- .../springboot/camel/OrderActivityImpl.java | 19 ------------------- .../springboot/camel/OrderRepository.java | 19 ------------------- .../springboot/camel/OrderWorkflow.java | 19 ------------------- .../springboot/camel/OrderWorkflowImpl.java | 19 ------------------- .../customize/CustomizeActivity.java | 19 ------------------- .../customize/CustomizeActivityImpl.java | 19 ------------------- .../customize/CustomizeWorkflow.java | 19 ------------------- .../customize/CustomizeWorkflowImpl.java | 19 ------------------- .../customize/TemporalOptionsConfig.java | 19 ------------------- .../springboot/hello/HelloActivity.java | 19 ------------------- .../springboot/hello/HelloActivityImpl.java | 19 ------------------- .../springboot/hello/HelloWorkflow.java | 19 ------------------- .../springboot/hello/HelloWorkflowImpl.java | 19 ------------------- .../springboot/hello/model/Person.java | 19 ------------------- .../springboot/kafka/KafkaActivity.java | 19 ------------------- .../springboot/kafka/KafkaActivityImpl.java | 19 ------------------- .../samples/springboot/kafka/KafkaConfig.java | 19 ------------------- .../springboot/kafka/MessageController.java | 19 ------------------- .../springboot/kafka/MessageWorkflow.java | 19 ------------------- .../springboot/kafka/MessageWorkflowImpl.java | 19 ------------------- ...ProductNotAvailableForAmountException.java | 19 ------------------- .../springboot/update/PurchaseActivities.java | 19 ------------------- .../update/PurchaseActivitiesImpl.java | 19 ------------------- .../springboot/update/PurchaseWorkflow.java | 19 ------------------- .../update/PurchaseWorkflowImpl.java | 19 ------------------- .../update/ResourceNotFoundException.java | 19 ------------------- .../springboot/update/model/Product.java | 19 ------------------- .../update/model/ProductRepository.java | 19 ------------------- .../springboot/update/model/Purchase.java | 19 ------------------- .../samples/springboot/CamelSampleTest.java | 19 ------------------- .../springboot/CustomizeSampleTest.java | 19 ------------------- .../samples/springboot/HelloSampleTest.java | 19 ------------------- .../HelloSampleTestMockedActivity.java | 19 ------------------- .../springboot/KafkaConsumerTestHelper.java | 19 ------------------- .../samples/springboot/KafkaSampleTest.java | 19 ------------------- .../samples/springboot/UpdateSampleTest.java | 19 ------------------- 411 files changed, 4 insertions(+), 7764 deletions(-) rename LICENSE.txt => LICENSE (91%) delete mode 100644 license-header.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e2e0df58..8fc0b023a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,8 @@ jobs: run: | docker compose -f ./docker/github/docker-compose.yaml up unit-test - copyright: - name: Copyright and code format + code_format: + name: Code format runs-on: ubuntu-latest timeout-minutes: 20 steps: @@ -47,4 +47,4 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Run copyright and code format checks - run: ./gradlew --no-daemon checkLicenseMain checkLicenses spotlessCheck \ No newline at end of file + run: ./gradlew --no-daemon spotlessCheck \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE similarity index 91% rename from LICENSE.txt rename to LICENSE index e89e81b36..e4f46f431 100644 --- a/LICENSE.txt +++ b/LICENSE @@ -1,6 +1,6 @@ Temporal Java SDK -Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved +Copyright (c) 2025 Temporal Technologies, Inc. All Rights Reserved Copyright (c) 2017 Uber Technologies, Inc. All Rights Reserved diff --git a/build.gradle b/build.gradle index f1731c4fd..a833ff3cd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,4 @@ plugins { - id 'org.cadixdev.licenser' version '0.6.1' id "net.ltgt.errorprone" version "4.0.1" id 'com.diffplug.spotless' version '6.25.0' apply false id "org.springframework.boot" version "${springBootPluginVersion}" @@ -7,7 +6,6 @@ plugins { subprojects { apply plugin: 'java' - apply plugin: 'org.cadixdev.licenser' apply plugin: 'net.ltgt.errorprone' apply plugin: 'com.diffplug.spotless' @@ -44,15 +42,6 @@ subprojects { } - license { - header rootProject.file('license-header.txt') - exclude '**/*.json' - exclude '**/*.yaml' - exclude '**/*.yml' - exclude '**/*.html' - exclude '**/*.js' - } - apply plugin: 'com.diffplug.spotless' spotless { diff --git a/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java b/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java index 5009d68d3..6b60caac2 100644 --- a/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java +++ b/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncchild; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java index 846ce39be..b375b3248 100644 --- a/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/asyncchild/ChildWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncchild; import io.temporal.workflow.Workflow; diff --git a/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java b/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java index 4a031bd08..6ac603ae8 100644 --- a/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java +++ b/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncchild; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java b/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java index 61dd13b3e..f98cffa0a 100644 --- a/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/asyncchild/ParentWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncchild; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/asyncchild/Starter.java b/core/src/main/java/io/temporal/samples/asyncchild/Starter.java index 126918043..b02f0dc4c 100644 --- a/core/src/main/java/io/temporal/samples/asyncchild/Starter.java +++ b/core/src/main/java/io/temporal/samples/asyncchild/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncchild; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflow.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflow.java index 9cd9d75d2..48b57a57d 100644 --- a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflow.java +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncuntypedchild; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflowImpl.java index 958bd0fc3..3f33a9470 100644 --- a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ChildWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncuntypedchild; import io.temporal.workflow.Workflow; diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java index b911ed234..10397b365 100644 --- a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncuntypedchild; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflowImpl.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflowImpl.java index 87cb9fd0f..d16e45137 100644 --- a/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncuntypedchild; import static io.temporal.samples.asyncuntypedchild.Starter.WORKFLOW_ID; diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java index 2453376ce..6cf9da20f 100644 --- a/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncuntypedchild; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java index 57ec84bb2..89bb5652c 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import static io.temporal.samples.batch.heartbeatingactivity.HeartbeatingActivityBatchWorker.TASK_QUEUE; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java index fad30f414..9d2d7b4e1 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java index 8d9d9f061..b201795d2 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java index 946f3fa20..345e97ea4 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java index b5e49918f..706ad7533 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import java.util.Optional; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java index 818507743..f72c3a719 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import java.util.Optional; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java index 6aa0241da..0c35b8cf9 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; /** A helper class that implements record processing. */ diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java index cc0678f8c..e31cd4758 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java index 4ec9b1bb6..49e70179e 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java index 5d534fffa..9008fb28a 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import org.slf4j.Logger; diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java index bec3fdd6c..1a1d6abfe 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; /** Record to process. A real application would add a use case specific data. */ diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java index 8e9530c36..c89fc590c 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import static io.temporal.samples.batch.iterator.IteratorBatchWorker.TASK_QUEUE; diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java index ecb9edf38..88b8eacb7 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java index c5d55de3a..991cdd257 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java index 44a56a5a8..fa294ec70 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java b/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java index 9f1974993..dc8ee0737 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java b/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java index 72fbd0189..b7102ce24 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import java.util.ArrayList; diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java b/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java index 703716a55..498da8567 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java index 12535f7aa..78e7eeb88 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import io.temporal.workflow.Workflow; diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java b/core/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java index ea40ee807..8379a0dd2 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; /** Record to process. A real application would add a use case specific data. */ diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java index a09b56479..4924e47a0 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import java.util.Set; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java index 40eb14c7b..fad65b362 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java index 2e96dc8ba..6838ce922 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java index 4f4013e56..98d720ed2 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/ProcessBatchInput.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import java.util.HashSet; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java index b9eece15d..276629534 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordIterable.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java index f0dbf70bc..c8257a570 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java index b97379574..169987ded 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import java.util.ArrayList; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java index e4647aa68..35945052f 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java index 94d294874..9bd767111 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.workflow.Workflow; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java index ab2f29636..9205051f3 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; /** Record to process. */ diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java index 8c3329c37..f4d689f4a 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import static io.temporal.samples.batch.slidingwindow.SlidingWindowBatchWorker.TASK_QUEUE; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java index 2b1b6c1c4..32dd8e09c 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java index 3a49126d6..5b1ac9723 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.workflow.QueryMethod; diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java index 91b6d9955..33bb42418 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/Booking.java b/core/src/main/java/io/temporal/samples/bookingsaga/Booking.java index 3b9eb73ff..7e4594a7d 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/Booking.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/Booking.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsaga; public final class Booking { diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java index b8e8db77f..31df78291 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsaga; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java index 5fbfd91bd..76115d15f 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsaga; import io.temporal.failure.ApplicationFailure; diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java index 075eaa718..b791065da 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsaga; import com.google.common.base.Throwables; diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java index abfe004a9..b538e0942 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsaga; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java index e9ec8f10e..dccffee77 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsaga; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java index b4558ed4a..1e13d6d75 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsaga; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java index a6a0a4e28..d096e4305 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsyncsaga; public final class Booking { diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivities.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivities.java index a826eb57e..cce0d8828 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivities.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsyncsaga; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivitiesImpl.java index bb0bc5de1..3ee3f73b3 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsyncsaga; import io.temporal.failure.ApplicationFailure; diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java index e4857c4ea..cebbc93b8 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsyncsaga; import com.google.common.base.Throwables; diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java index 263d4e405..151bd62ae 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsyncsaga; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java index 99ab6bf79..933f67bb1 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsyncsaga; import io.temporal.workflow.UpdateMethod; diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowImpl.java index 8f8c640cc..e6971b3f0 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsyncsaga; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java b/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java index 4a56eb83a..9be315a8a 100644 --- a/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java +++ b/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.common; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java b/core/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java index d0bbf7f3b..d47b876c5 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/ClientCounter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import java.util.AbstractMap; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java b/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java index c3c8280c7..bf8ddd793 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java index c6deda735..5c9d457fe 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.WorkflowClientCallsInterceptor; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java index aafc7625c..6757db210 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.WorkflowClientCallsInterceptor; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java index a866680ff..2793d6ff4 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import io.temporal.activity.ActivityExecutionContext; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java index 156002e42..6b48ff1ac 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.*; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java index 8acd6d177..ff4cc4942 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowInboundCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java index 1add50445..2ddc564f6 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java b/core/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java index d6d35abfd..4b7a4a779 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/WorkerCounter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import java.util.AbstractMap; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java b/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java index 5935003e9..6ff303e71 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor.activities; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java b/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java index b2ca5edf2..6ab501d53 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor.activities; public class MyActivitiesImpl implements MyActivities { diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java index 36e5099da..0434026f8 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor.workflow; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java index d4a944071..68cdf7c02 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor.workflow; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java index 8541fc604..5714391f5 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor.workflow; import io.temporal.workflow.QueryMethod; diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java index f20876e16..f187af94c 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor.workflow; import io.temporal.workflow.ChildWorkflowOptions; diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java index d42d0455f..5d49812cc 100644 --- a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.customchangeversion; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java index 874171ff3..113d306bd 100644 --- a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.customchangeversion; public class CustomChangeVersionActivitiesImpl implements CustomChangeVersionActivities { diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java index e1200360b..82921b8dc 100644 --- a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.customchangeversion; import io.grpc.StatusRuntimeException; diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java index 20d090990..cd9703973 100644 --- a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.customchangeversion; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflowImpl.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflowImpl.java index 51d3ca3eb..c72673899 100644 --- a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.customchangeversion; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/dsl/DslActivities.java b/core/src/main/java/io/temporal/samples/dsl/DslActivities.java index dce8e8bae..0fb98f114 100644 --- a/core/src/main/java/io/temporal/samples/dsl/DslActivities.java +++ b/core/src/main/java/io/temporal/samples/dsl/DslActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.dsl; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java b/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java index 77aa5df06..d02116316 100644 --- a/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.dsl; import java.util.concurrent.TimeUnit; diff --git a/core/src/main/java/io/temporal/samples/dsl/DslWorkflow.java b/core/src/main/java/io/temporal/samples/dsl/DslWorkflow.java index 9863a43db..22745b809 100644 --- a/core/src/main/java/io/temporal/samples/dsl/DslWorkflow.java +++ b/core/src/main/java/io/temporal/samples/dsl/DslWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.dsl; import io.temporal.samples.dsl.model.Flow; diff --git a/core/src/main/java/io/temporal/samples/dsl/DslWorkflowImpl.java b/core/src/main/java/io/temporal/samples/dsl/DslWorkflowImpl.java index e89d9c52e..db75fab37 100644 --- a/core/src/main/java/io/temporal/samples/dsl/DslWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/dsl/DslWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.dsl; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/dsl/Starter.java b/core/src/main/java/io/temporal/samples/dsl/Starter.java index 47b2a5035..e0336d659 100644 --- a/core/src/main/java/io/temporal/samples/dsl/Starter.java +++ b/core/src/main/java/io/temporal/samples/dsl/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.dsl; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/core/src/main/java/io/temporal/samples/dsl/model/Flow.java b/core/src/main/java/io/temporal/samples/dsl/model/Flow.java index 22e9d3254..a458c0124 100644 --- a/core/src/main/java/io/temporal/samples/dsl/model/Flow.java +++ b/core/src/main/java/io/temporal/samples/dsl/model/Flow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.dsl.model; import java.util.List; diff --git a/core/src/main/java/io/temporal/samples/dsl/model/FlowAction.java b/core/src/main/java/io/temporal/samples/dsl/model/FlowAction.java index f1f9a367c..c85bf8b6f 100644 --- a/core/src/main/java/io/temporal/samples/dsl/model/FlowAction.java +++ b/core/src/main/java/io/temporal/samples/dsl/model/FlowAction.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.dsl.model; public class FlowAction { diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java index 36da78d87..623efa310 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java index 222368ec6..97ef9320a 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/Transaction.java b/core/src/main/java/io/temporal/samples/earlyreturn/Transaction.java index 0f910b4fd..a005c6808 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/Transaction.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/Transaction.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java index 8f3e866f8..4b7f26997 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivitiesImpl.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivitiesImpl.java index 52dc61806..33c3d3435 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import io.temporal.failure.ApplicationFailure; diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java index c174a63f8..5f01ae66e 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java index 2d1ef6f5f..28d4f3321 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import io.temporal.workflow.UpdateMethod; diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflowImpl.java b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflowImpl.java index 8f7c86d34..9a162687b 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java b/core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java index 04c9a9862..6a815c62d 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java b/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java index d302fc8fe..0b6ad7b25 100644 --- a/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java +++ b/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encodefailures; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java b/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java index ab3571c5d..72eb1b689 100644 --- a/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java +++ b/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encodefailures; import io.temporal.workflow.Workflow; diff --git a/core/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java b/core/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java index d8eefbdd5..20ad3a2ce 100644 --- a/core/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java +++ b/core/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encodefailures; public class InvalidCustomerException extends Exception { diff --git a/core/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java b/core/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java index 30a6def44..a61503c77 100644 --- a/core/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java +++ b/core/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encodefailures; public class MyCustomer { diff --git a/core/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java b/core/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java index a25bccef4..7c5984e23 100644 --- a/core/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java +++ b/core/src/main/java/io/temporal/samples/encodefailures/SimplePrefixPayloadCodec.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encodefailures; import com.google.protobuf.ByteString; diff --git a/core/src/main/java/io/temporal/samples/encodefailures/Starter.java b/core/src/main/java/io/temporal/samples/encodefailures/Starter.java index 5bdd35888..9e4e17fe0 100644 --- a/core/src/main/java/io/temporal/samples/encodefailures/Starter.java +++ b/core/src/main/java/io/temporal/samples/encodefailures/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encodefailures; import io.temporal.api.common.v1.Payload; diff --git a/core/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java b/core/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java index e8fc71c7a..96f445a46 100644 --- a/core/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java +++ b/core/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encryptedpayloads; import com.google.protobuf.ByteString; diff --git a/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java b/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java index 88c8a1d78..00636fb29 100644 --- a/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java +++ b/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encryptedpayloads; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java index 164b4972d..b4bd1e825 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java index 118cd7279..dd3a3f0d2 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.activities; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java index 1d5fc7025..d00fd5d71 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.activities; public class ForInterceptorActivitiesImpl implements ForInterceptorActivities { diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java index 106916fc8..94d090a67 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.activities; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java index 48fe29a86..cfa787d0d 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.activities; public class MyActivitiesImpl implements MyActivities { diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyActivityInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyActivityInboundCallsInterceptor.java index 69c79429a..91058012b 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyActivityInboundCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyActivityInboundCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.interceptor; import io.temporal.activity.ActivityExecutionContext; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java index 761f39b70..a52e17c2d 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.interceptor; import io.temporal.common.interceptors.*; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowInboundCallsInterceptor.java index 023a098bf..7c3bc47e6 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowInboundCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowInboundCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.interceptor; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowOutboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowOutboundCallsInterceptor.java index 9d99acb8a..bca1503b3 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowOutboundCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkflowOutboundCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.interceptor; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java index 6c334f97a..f0eeff451 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.workflows; import io.temporal.workflow.WorkflowMethod; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java index d7be4d3d0..acc5c4379 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.workflows; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java index 1409bce40..f4d7960dc 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.workflows; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java index 07d6b8dc6..4acb44493 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.workflows; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java index e4b012b99..a976353b3 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor.workflows; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java index aa1f370ee..f2c1ee95a 100644 --- a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java +++ b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.fileprocessing; import static io.temporal.samples.fileprocessing.FileProcessingWorker.TASK_QUEUE; diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java index 55b2123fa..b154a2c23 100644 --- a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java +++ b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.fileprocessing; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java index e684ac0c7..c9e88cd58 100644 --- a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java +++ b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.fileprocessing; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java index f93c3ae63..b810baed8 100644 --- a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.fileprocessing; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java b/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java index 1326a8ad7..e66e5b727 100644 --- a/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java +++ b/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.fileprocessing; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java b/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java index 905642785..965f4f782 100644 --- a/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.fileprocessing; import com.google.common.io.Files; diff --git a/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java b/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java index 2dd9455ec..9578fee01 100644 --- a/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java +++ b/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.getresultsasync; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java index 1036cb185..de362b34f 100644 --- a/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.getresultsasync; import io.temporal.workflow.Workflow; diff --git a/core/src/main/java/io/temporal/samples/getresultsasync/Starter.java b/core/src/main/java/io/temporal/samples/getresultsasync/Starter.java index 573cc7e90..79ac70171 100644 --- a/core/src/main/java/io/temporal/samples/getresultsasync/Starter.java +++ b/core/src/main/java/io/temporal/samples/getresultsasync/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.getresultsasync; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java b/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java index 8edb69dbc..d9bb276be 100644 --- a/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java +++ b/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.getresultsasync; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java b/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java index c5561df09..38ea8f097 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java index 70f2ebfa0..3c890d3ab 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java index 0af214471..1da873e2c 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java index e7ca4a9d4..f7f01b3a3 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsync.java b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java index 99b1e8928..7b068f7bf 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsync.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java index b2409487d..87f9cbee7 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.*; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java index cf860d06a..4da2b6ee1 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAwait.java b/core/src/main/java/io/temporal/samples/hello/HelloAwait.java index 5868534c8..069f5bb65 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAwait.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAwait.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java index d7b31ce88..59cc0c7c8 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java index 0f70bd814..6efb24b0a 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.*; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloChild.java b/core/src/main/java/io/temporal/samples/hello/HelloChild.java index a916c13c8..f631f5cbe 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloChild.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloChild.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCron.java b/core/src/main/java/io/temporal/samples/hello/HelloCron.java index 5e7c9aa01..1d46d1c33 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloCron.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloCron.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java b/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java index a0b850854..13d3d9041 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java index 45f4c7509..8baaf2364 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java index c88a79b5e..f770f4263 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java b/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java index c901753a3..feb0d45f1 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloException.java b/core/src/main/java/io/temporal/samples/hello/HelloException.java index 33dd03b92..8c1daaccb 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloException.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloException.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import com.google.common.base.Throwables; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java index 7925712e0..9436eab6b 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java index 6925cef1c..ab3e7c789 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java b/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java index f94e6b66b..418244684 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java index 8a4ad611d..a6bb70f1f 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloQuery.java b/core/src/main/java/io/temporal/samples/hello/HelloQuery.java index 5ee640e14..012ae1b97 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloQuery.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloQuery.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSaga.java b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java index d0180e35d..5dfc0848b 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSaga.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java b/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java index 22a86f61f..7d3c5ef1a 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java index e9d28cc01..e2b1c0f9c 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java index faa36f005..e0c39bf91 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignal.java b/core/src/main/java/io/temporal/samples/hello/HelloSignal.java index a302816dd..cd5a488ab 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSignal.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSignal.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java index 804034ffa..26c22b2a2 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java index df196d762..f0dfb76c4 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java b/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java index 79f20336b..329569738 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import com.google.common.base.Throwables; diff --git a/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java index a03a8104b..94570db98 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.activity.*; diff --git a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java index 6052c9d7f..f36f3176c 100644 --- a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java +++ b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.keymanagementencryption.awsencryptionsdk; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/KeyringCodec.java b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/KeyringCodec.java index e8d669408..a7c9988bd 100644 --- a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/KeyringCodec.java +++ b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/KeyringCodec.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.keymanagementencryption.awsencryptionsdk; import com.amazonaws.encryptionsdk.AwsCrypto; diff --git a/core/src/main/java/io/temporal/samples/listworkflows/Customer.java b/core/src/main/java/io/temporal/samples/listworkflows/Customer.java index 6ec0780fb..6777bcb55 100644 --- a/core/src/main/java/io/temporal/samples/listworkflows/Customer.java +++ b/core/src/main/java/io/temporal/samples/listworkflows/Customer.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.listworkflows; public class Customer { diff --git a/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java b/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java index 609b4a86f..a49c8f479 100644 --- a/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java +++ b/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.listworkflows; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java b/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java index f7151c4b1..c4de12e50 100644 --- a/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.listworkflows; import java.util.concurrent.TimeUnit; diff --git a/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java b/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java index 1c4a4fe23..62d1a29fc 100644 --- a/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.listworkflows; import io.temporal.workflow.SignalMethod; diff --git a/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java index 7b43ff650..d3871d0e0 100644 --- a/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.listworkflows; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/listworkflows/Starter.java b/core/src/main/java/io/temporal/samples/listworkflows/Starter.java index d03039a7a..1d9ef916c 100644 --- a/core/src/main/java/io/temporal/samples/listworkflows/Starter.java +++ b/core/src/main/java/io/temporal/samples/listworkflows/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.listworkflows; import io.temporal.api.enums.v1.WorkflowExecutionStatus; diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java index 489463d31..a213c3f81 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.metrics; import com.sun.net.httpserver.HttpServer; diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java b/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java index 03c20d481..621fab684 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.metrics; import static java.nio.charset.StandardCharsets.UTF_8; diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java index eced332dd..4b5f3173f 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.metrics; import com.sun.net.httpserver.HttpServer; diff --git a/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java b/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java index 7a1f77521..113a4d05d 100644 --- a/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java +++ b/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.metrics.activities; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java b/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java index 1844a44e8..fd9edded4 100644 --- a/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.metrics.activities; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java b/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java index bc97521b5..da1e473f2 100644 --- a/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java +++ b/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.metrics.workflow; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java b/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java index 560d013d6..7bd7b2472 100644 --- a/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.metrics.workflow; import com.uber.m3.tally.Scope; diff --git a/core/src/main/java/io/temporal/samples/moneybatch/Account.java b/core/src/main/java/io/temporal/samples/moneybatch/Account.java index 98565e906..fd4bd1145 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/Account.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/Account.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneybatch; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java index f0aa2eb9f..ecee1ad05 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneybatch; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java index 1e03f516d..694fb1d33 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneybatch; public class AccountImpl implements Account { diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java index c69ed6ee0..d9c5ef7cd 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneybatch; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java index a3278cb7c..c3ebc35ab 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneybatch; import io.temporal.workflow.QueryMethod; diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java index 2d979bd21..fe1ab1241 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneybatch; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java b/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java index 7db5bd037..8a63c02e3 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneybatch; import io.temporal.client.BatchRequest; diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/Account.java b/core/src/main/java/io/temporal/samples/moneytransfer/Account.java index 507ceb53b..413d1bfe3 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/Account.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/Account.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneytransfer; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java index dcd5cd43e..a2bbee418 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneytransfer; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java index 761c06b3a..8374ab90f 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneytransfer; public class AccountImpl implements Account { diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java index b7aaf0fad..6d237d8fa 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneytransfer; import static io.temporal.samples.moneytransfer.AccountActivityWorker.TASK_QUEUE; diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java index 554ea54ac..e5a5cfe26 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneytransfer; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java index bf7a042fe..a5de72543 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneytransfer; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java b/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java index 1faa9cd3b..b333b9341 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneytransfer; import static io.temporal.samples.moneytransfer.AccountActivityWorker.TASK_QUEUE; diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java index 5c65df949..be1cc788e 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.caller; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java index e7be0ae4a..55186489e 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.caller; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java index 5f830855e..b4c7fac84 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.caller; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java index 7c5d5f787..948008772 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.caller; import io.temporal.samples.nexus.service.NexusService; diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java index 6e943c17e..173c0be8b 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.caller; import io.temporal.samples.nexus.service.NexusService; diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java index 5b9048d60..f1612e359 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.caller; import io.temporal.samples.nexus.service.NexusService; diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java index 71a78f91b..3d8afa3d7 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.handler; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java index caa34d985..3cae13b31 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.handler; import io.temporal.samples.nexus.service.NexusService; diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java index ea5203eb7..c897a5181 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.handler; import io.temporal.failure.ApplicationFailure; diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java index e4a58ae95..2344f27ec 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.handler; import io.nexusrpc.handler.OperationHandler; diff --git a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java index 812eb4949..5d382eaab 100644 --- a/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java +++ b/core/src/main/java/io/temporal/samples/nexus/options/ClientOptions.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.options; import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; diff --git a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java b/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java index e12dcbe92..ad65b1b33 100644 --- a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java +++ b/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.service; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java index 1ee705b1a..c0cd95dde 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscancellation.caller; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java index 37f5eaa5f..cb05189cf 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscancellation.caller; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java index 7f77cc68c..a585d713c 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscancellation.caller; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java index bc3666147..c3dc6440c 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscancellation.caller; import static io.temporal.samples.nexus.service.NexusService.Language.*; diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java index a70a47abe..8b8949a70 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscancellation.handler; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java index 246c25e93..406b4b20b 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscancellation.handler; import io.temporal.failure.ApplicationFailure; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java index 9a765c9c3..f0896221a 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.caller; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java index 86fc0b064..13e568822 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.caller; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java index 23cb2ce49..14e998629 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.caller; import io.temporal.samples.nexus.caller.EchoCallerWorkflow; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java index 0fec8c7d4..fedefbc34 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.caller; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java index e476924e1..c4f9ef54c 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.handler; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java index 389368b50..a2db3cb0e 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.handler; import io.temporal.failure.ApplicationFailure; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java index b4ac16493..4977ff0c0 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.handler; import io.nexusrpc.handler.OperationHandler; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/MDCContextPropagator.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/MDCContextPropagator.java index a8b65be2f..fe1cd54af 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/MDCContextPropagator.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/MDCContextPropagator.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.propagation; import io.temporal.api.common.v1.Payload; diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/NexusMDCContextInterceptor.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/NexusMDCContextInterceptor.java index f2fa07f23..e252af2cc 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/NexusMDCContextInterceptor.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/propagation/NexusMDCContextInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexuscontextpropagation.propagation; import io.nexusrpc.OperationException; diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java index 455581e65..052445724 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter.cloudevents; import io.cloudevents.CloudEvent; diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java index f307aa5b6..d22644741 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter.cloudevents; import io.cloudevents.CloudEvent; diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java index 39659c64f..c1a06a780 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CloudEventsPayloadConverter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter.cloudevents; import com.google.protobuf.ByteString; diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java index 630407e0e..2e17f4cb0 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter.cloudevents; import io.cloudevents.CloudEvent; diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java index c6f11cc8c..c1445a9dd 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter.crypto; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java index fbf35f779..5ab041c55 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter.crypto; public class CryptoWorkflowImpl implements CryptoWorkflow { diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java index d3096a12c..a9cf46cf1 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter.crypto; import com.codingrodent.jackson.crypto.Encrypt; diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java index 3940c0f79..dffdb41a1 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter.crypto; import com.codingrodent.jackson.crypto.CryptoModule; diff --git a/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java b/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java index 109ec98ae..08dc596ba 100644 --- a/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java +++ b/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.peractivityoptions; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java index 928b735f5..8e8810566 100644 --- a/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.peractivityoptions; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java b/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java index 6c54ba0ce..b2bb7fd79 100644 --- a/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java +++ b/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.peractivityoptions; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java b/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java index 48f0e6bdf..1fa28beb1 100644 --- a/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.peractivityoptions; import io.temporal.failure.ActivityFailure; diff --git a/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java b/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java index c99bc0206..7db5df86d 100644 --- a/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java +++ b/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.peractivityoptions; import com.google.common.collect.ImmutableMap; diff --git a/core/src/main/java/io/temporal/samples/polling/PollingActivities.java b/core/src/main/java/io/temporal/samples/polling/PollingActivities.java index e105e220e..a0fc767e6 100644 --- a/core/src/main/java/io/temporal/samples/polling/PollingActivities.java +++ b/core/src/main/java/io/temporal/samples/polling/PollingActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/polling/PollingWorkflow.java b/core/src/main/java/io/temporal/samples/polling/PollingWorkflow.java index c68adf955..10ed346a6 100644 --- a/core/src/main/java/io/temporal/samples/polling/PollingWorkflow.java +++ b/core/src/main/java/io/temporal/samples/polling/PollingWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/polling/TestService.java b/core/src/main/java/io/temporal/samples/polling/TestService.java index 829bfc9d4..ec48baed5 100644 --- a/core/src/main/java/io/temporal/samples/polling/TestService.java +++ b/core/src/main/java/io/temporal/samples/polling/TestService.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling; import java.util.concurrent.ThreadLocalRandom; diff --git a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java index fe3c85e5b..f5b3fbb2b 100644 --- a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.frequent; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java index a795348c4..4a52cab2f 100644 --- a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java +++ b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.frequent; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java index b50f538c3..1bab28261 100644 --- a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.frequent; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java index 687573b9d..5b9a5b0cd 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.infrequent; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java index 096ea2c4c..2a6cb7a85 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.infrequent; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java index 7d1854558..8831fd4ff 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.infrequent; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java index 41cbba1f2..a202e0b71 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.infrequentwithretryafter; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java index ff8d0dd73..81853ec71 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.infrequentwithretryafter; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterWorkflowImpl.java index 96ff76968..34042c10c 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.infrequentwithretryafter; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java index c8a999a4c..272bc4cef 100644 --- a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.periodicsequence; import io.temporal.activity.Activity; diff --git a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java index a877946ee..e36f18ae6 100644 --- a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingChildWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.periodicsequence; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java index ef251260f..f2ef3eb1f 100644 --- a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java +++ b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.periodicsequence; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java index cb7549b1f..7be46d245 100644 --- a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.periodicsequence; import io.temporal.samples.polling.PollingWorkflow; diff --git a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java index c0291a305..2e6a55b3b 100644 --- a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java +++ b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling.periodicsequence; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java index 78bc3b7c7..cd3e546da 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java index 515d93b33..f6a4f8201 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java index 2e120c353..494dcc653 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import io.temporal.failure.ApplicationFailure; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java index b9449b3c0..4dae45a5b 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java index b12ee8307..3db46cf51 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java index f191ba1ad..42fd358bd 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java index 06adda488..c54f8d0ab 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java index 8b56cd0cd..ba55e32bc 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import io.temporal.workflow.QueryMethod; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java index 180306447..1875d8813 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import io.temporal.common.interceptors.*; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java index 7b62aee9f..776c7e5d3 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java index a7ac7e33c..9bc9212c3 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowOutboundCallsInterceptor.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import com.google.common.base.Throwables; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java index f5113d3a4..b0cf85ef8 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivities.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivities.java index 267a9626f..2a76cede2 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivities.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.safemessagepassing; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivitiesImpl.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivitiesImpl.java index 827ea2e1b..c82380577 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.safemessagepassing; import java.util.Set; diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java index afe42b37c..33ddb95be 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.safemessagepassing; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowImpl.java index d25453eca..e27ad5ac4 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.safemessagepassing; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java index ea3aa4437..1913a3e40 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.safemessagepassing; import static io.temporal.samples.safemessagepassing.ClusterManagerWorkflowWorker.CLUSTER_MANAGER_WORKFLOW_ID; diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java index ae98968e4..2f063a663 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.safemessagepassing; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java b/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java index 94eba7746..984f2e8ff 100644 --- a/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java +++ b/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.sleepfordays; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java b/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java index a8cd72536..52600f991 100644 --- a/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.sleepfordays; public class SendEmailActivityImpl implements SendEmailActivity { diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java b/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java index 2828a3ada..6814e76f3 100644 --- a/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java +++ b/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.sleepfordays; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java b/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java index 1bced9729..e7c82669f 100644 --- a/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java +++ b/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.sleepfordays; import io.temporal.workflow.SignalMethod; diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java b/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java index a9660de7c..cf5e9a9a7 100644 --- a/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java +++ b/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.sleepfordays; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java b/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java index 28ae326cc..301326c27 100644 --- a/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java +++ b/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.sleepfordays; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java b/core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java index a816ed45a..146ccc056 100644 --- a/core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java +++ b/core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.ssl; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java index 645e6a946..701cc2f60 100644 --- a/core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.ssl; public class MyWorkflowImpl implements MyWorkflow { diff --git a/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java b/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java index 165737ffa..427fefcb8 100644 --- a/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java +++ b/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.ssl; import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; diff --git a/core/src/main/java/io/temporal/samples/ssl/Starter.java b/core/src/main/java/io/temporal/samples/ssl/Starter.java index ca748ffc3..c69101473 100644 --- a/core/src/main/java/io/temporal/samples/ssl/Starter.java +++ b/core/src/main/java/io/temporal/samples/ssl/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.ssl; import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; diff --git a/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java b/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java index 4c517bd67..b22060095 100644 --- a/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java +++ b/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.terminateworkflow; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java index a254f1e34..82e6159e8 100644 --- a/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.terminateworkflow; import io.temporal.workflow.Workflow; diff --git a/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java b/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java index 3b9d17fed..20f0d171d 100644 --- a/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java +++ b/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.terminateworkflow; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/main/java/io/temporal/samples/tracing/JaegerUtils.java b/core/src/main/java/io/temporal/samples/tracing/JaegerUtils.java index 862c4d0c1..0b64b604c 100644 --- a/core/src/main/java/io/temporal/samples/tracing/JaegerUtils.java +++ b/core/src/main/java/io/temporal/samples/tracing/JaegerUtils.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing; import io.jaegertracing.internal.JaegerTracer; diff --git a/core/src/main/java/io/temporal/samples/tracing/Starter.java b/core/src/main/java/io/temporal/samples/tracing/Starter.java index 62b251d00..ebb830c19 100644 --- a/core/src/main/java/io/temporal/samples/tracing/Starter.java +++ b/core/src/main/java/io/temporal/samples/tracing/Starter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java b/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java index 26cbfe8b3..221c3efef 100644 --- a/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java +++ b/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java index a0a59c746..af9f8d9ba 100644 --- a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java +++ b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing.workflow; import io.temporal.activity.ActivityInterface; diff --git a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java index a72763370..83af9d490 100644 --- a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java +++ b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing.workflow; public class TracingActivitiesImpl implements TracingActivities { diff --git a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java index bb5ef68b4..a02448957 100644 --- a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java +++ b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing.workflow; import io.temporal.workflow.WorkflowInterface; diff --git a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java index a6f49c6d3..e170b4e84 100644 --- a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing.workflow; import io.temporal.activity.ActivityOptions; diff --git a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java index f6d983f99..69a50f3b1 100644 --- a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java +++ b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing.workflow; import io.temporal.workflow.QueryMethod; diff --git a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java index a02886013..86d440ab6 100644 --- a/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing.workflow; import io.temporal.workflow.ChildWorkflowOptions; diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java index b296a9e2b..9fa4a947f 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.updatabletimer; import io.temporal.workflow.QueryMethod; diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java index ad47eb88f..487f99640 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.updatabletimer; public class DynamicSleepWorkflowImpl implements DynamicSleepWorkflow { diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java index 5f0897051..d1f38e1ab 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.updatabletimer; import static io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker.DYNAMIC_SLEEP_WORKFLOW_ID; diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java index 14429ea0e..d0a4e712b 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.updatabletimer; import io.temporal.client.WorkflowClient; diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java b/core/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java index 0a81c7c9d..3a117d2e0 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.updatabletimer; import io.temporal.workflow.Workflow; diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java b/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java index 5f612aaf1..0a13ff071 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.updatabletimer; import static io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker.DYNAMIC_SLEEP_WORKFLOW_ID; diff --git a/core/src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java b/core/src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java index ef899fa20..f827cec9d 100644 --- a/core/src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java +++ b/core/src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncchild; import static org.junit.Assert.assertNotNull; diff --git a/core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java b/core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java index 12281dbcf..8740d23a1 100644 --- a/core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java +++ b/core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.asyncuntypedchild; import static io.temporal.api.enums.v1.WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_RUNNING; diff --git a/core/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java b/core/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java index 1de5d5360..f9a7fa309 100644 --- a/core/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.heartbeatingactivity; import static io.temporal.samples.batch.heartbeatingactivity.RecordLoaderImpl.RECORD_COUNT; diff --git a/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java b/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java index 91cae65b7..12ff30b3b 100644 --- a/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/batch/iterator/IteratorIteratorBatchWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.iterator; import static io.temporal.samples.batch.iterator.RecordLoaderImpl.PAGE_COUNT; diff --git a/core/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java b/core/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java index ae48290e2..5104d3739 100644 --- a/core/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.batch.slidingwindow; import static org.junit.Assert.assertTrue; diff --git a/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java b/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java index 7a2d2cca6..a15f3de6e 100644 --- a/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsaga; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowTest.java b/core/src/test/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowTest.java index 8a170c169..5f2431e2c 100644 --- a/core/src/test/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.bookingsyncsaga; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/core/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java b/core/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java index 4ec530a4c..28369109d 100644 --- a/core/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java +++ b/core/src/test/java/io/temporal/samples/countinterceptor/ClientCountInterceptorTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java b/core/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java index 4ec0f90d4..80a3184d2 100644 --- a/core/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java +++ b/core/src/test/java/io/temporal/samples/countinterceptor/WorkerCountInterceptorTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.countinterceptor; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java b/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java index 808504a3f..1affc9bdb 100644 --- a/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/dsl/DslWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.dsl; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java b/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java index 97cda3583..fe4a27964 100644 --- a/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/earlyreturn/TransactionWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.earlyreturn; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java b/core/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java index cb0514134..9c365decf 100644 --- a/core/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java +++ b/core/src/test/java/io/temporal/samples/encodefailures/EncodeFailuresTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.encodefailures; import static org.junit.Assert.assertThrows; diff --git a/core/src/test/java/io/temporal/samples/excludefrominterceptor/ExcludeFromInterceptorTest.java b/core/src/test/java/io/temporal/samples/excludefrominterceptor/ExcludeFromInterceptorTest.java index d77b6e41c..3405fb9fc 100644 --- a/core/src/test/java/io/temporal/samples/excludefrominterceptor/ExcludeFromInterceptorTest.java +++ b/core/src/test/java/io/temporal/samples/excludefrominterceptor/ExcludeFromInterceptorTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.excludefrominterceptor; import io.temporal.api.enums.v1.EventType; diff --git a/core/src/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java b/core/src/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java index 1166bf875..16f3cb0f2 100644 --- a/core/src/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java +++ b/core/src/test/java/io/temporal/samples/fileprocessing/FileProcessingTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.fileprocessing; import static org.mockito.ArgumentMatchers.any; diff --git a/core/src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java b/core/src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java index fe54b1884..b03a84df8 100644 --- a/core/src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java +++ b/core/src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.getresultsasync; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloAccumulatorTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAccumulatorTest.java index 53477bbd7..1ae96970f 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloAccumulatorTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloAccumulatorTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static io.temporal.samples.hello.HelloAccumulator.MAX_AWAIT_TIME; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java index 0a25cd7fc..59395ddf4 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java index 1549fd6e4..b57bca885 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static io.temporal.samples.hello.HelloActivityExclusiveChoice.WORKFLOW_ID; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java index 88dcc3a5e..4efd978db 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloActivityJUnit5Test.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java index 977d41708..0b859d217 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloActivityReplayTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java index bd7645899..434ec41fa 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloActivityRetryTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloActivityTest.java b/core/src/test/java/io/temporal/samples/hello/HelloActivityTest.java index 506f2d75e..93f20e9d0 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloActivityTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloActivityTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java index 314cf0647..bdb90e2dd 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloAsyncActivityCompletionTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java index 48ec3142d..455a014ec 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloAsyncLambdaTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloAsyncTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAsyncTest.java index 892e4c58f..1c6c13239 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloAsyncTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloAsyncTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloAwaitTest.java b/core/src/test/java/io/temporal/samples/hello/HelloAwaitTest.java index 1912a942d..9e319eaaf 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloAwaitTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloAwaitTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java b/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java index 1af296fa8..c77e69b28 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertTrue; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeWithTimerTest.java b/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeWithTimerTest.java index 4c6e2bd79..73600c785 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeWithTimerTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloCancellationScopeWithTimerTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertTrue; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java index 7330120e5..63f87a7d0 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloChildJUnit5Test.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.mockito.Mockito.*; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java b/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java index 829f4aa10..1603fc7bb 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloChildTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloCronTest.java b/core/src/test/java/io/temporal/samples/hello/HelloCronTest.java index 26e69a570..02ebd266a 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloCronTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloCronTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static io.temporal.samples.hello.HelloCron.WORKFLOW_ID; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloDelayedStartTest.java b/core/src/test/java/io/temporal/samples/hello/HelloDelayedStartTest.java index 273b351e8..c9f552af1 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloDelayedStartTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloDelayedStartTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java b/core/src/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java index 3c1395afb..5ce8acc4b 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloDetachedCancellationScopeTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java b/core/src/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java index afae8a43d..f3639116c 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloDynamicActivityJUnit5Test.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java b/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java index 96e3513b9..4ec529ed0 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloDynamicTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloEagerWorkflowStartTest.java b/core/src/test/java/io/temporal/samples/hello/HelloEagerWorkflowStartTest.java index 563d23824..da20545ae 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloEagerWorkflowStartTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloEagerWorkflowStartTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java b/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java index 7fef3c8b1..2a8108a66 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloExceptionTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java b/core/src/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java index a2a756117..4e15ad296 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloLocalActivityTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java b/core/src/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java index 52656f0e8..7ee1d5703 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloParallelActivityTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloPeriodicTest.java b/core/src/test/java/io/temporal/samples/hello/HelloPeriodicTest.java index 7d6cc1144..ed9eeeecc 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloPeriodicTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloPeriodicTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static io.temporal.samples.hello.HelloPeriodic.*; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java b/core/src/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java index 250fd8528..ecedb9172 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloPolymorphicActivityTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloQueryTest.java b/core/src/test/java/io/temporal/samples/hello/HelloQueryTest.java index e226bc4d0..2c7980326 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloQueryTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloQueryTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java index 40fd62264..b1bacd2c6 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloSearchAttributesTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static io.temporal.samples.hello.HelloSearchAttributes.getKeywordFromSearchAttribute; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java index 4672492e2..59ac0d396 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloSignalTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSignalTest.java index 89676c024..de674fcae 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloSignalTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloSignalTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloSignalWithTimerTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSignalWithTimerTest.java index c65fec165..dbf0578a0 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloSignalWithTimerTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloSignalWithTimerTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.api.common.v1.WorkflowExecution; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloUpdateTest.java b/core/src/test/java/io/temporal/samples/hello/HelloUpdateTest.java index fb41b2dd5..6411181d5 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloUpdateTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloUpdateTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java b/core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java index 7e0954494..77fbefcc7 100644 --- a/core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java +++ b/core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.hello; import io.temporal.client.WorkflowOptions; diff --git a/core/src/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java b/core/src/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java index f56cf3192..b7f7b66b1 100644 --- a/core/src/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java +++ b/core/src/test/java/io/temporal/samples/listworkflows/ListWorkflowsTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.listworkflows; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java b/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java index 86b13b3b6..21a4be616 100644 --- a/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java +++ b/core/src/test/java/io/temporal/samples/metrics/MetricsTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.metrics; import static junit.framework.TestCase.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java b/core/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java index ffe5ca44b..282a2136e 100644 --- a/core/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneybatch; import static org.mockito.ArgumentMatchers.any; diff --git a/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java b/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java index f69fea2b2..65b86daf6 100644 --- a/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.moneytransfer; import static org.mockito.ArgumentMatchers.eq; diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java index ba1bba461..2d3a6e42a 100644 --- a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.nexus.caller; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java b/core/src/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java index 391f23ec4..cc78ba75e 100644 --- a/core/src/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java +++ b/core/src/test/java/io/temporal/samples/payloadconverter/CloudEventsPayloadConverterTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java b/core/src/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java index 0693fa269..d8e765d1f 100644 --- a/core/src/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java +++ b/core/src/test/java/io/temporal/samples/payloadconverter/CryptoPayloadConverterTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.payloadconverter; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java b/core/src/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java index 1b2c4953f..fda95f010 100644 --- a/core/src/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java +++ b/core/src/test/java/io/temporal/samples/peractivityoptions/PerActivityOptionsTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.peractivityoptions; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/polling/FrequentPollingTest.java b/core/src/test/java/io/temporal/samples/polling/FrequentPollingTest.java index aeb2f27fb..b6de36d26 100644 --- a/core/src/test/java/io/temporal/samples/polling/FrequentPollingTest.java +++ b/core/src/test/java/io/temporal/samples/polling/FrequentPollingTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java b/core/src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java index a06de964d..2839d75a4 100644 --- a/core/src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java +++ b/core/src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java b/core/src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java index 959984a27..c9599ba56 100644 --- a/core/src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java +++ b/core/src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.polling; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java b/core/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java index 1e7696194..b65e0658f 100644 --- a/core/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java +++ b/core/src/test/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.retryonsignalinterceptor; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java b/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java index 55ea41fd9..be7219524 100644 --- a/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java +++ b/core/src/test/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorkerTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.safemessagepassing; import io.temporal.client.*; diff --git a/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysJUnit5Test.java b/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysJUnit5Test.java index 44e1f9e68..304eab6f3 100644 --- a/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysJUnit5Test.java +++ b/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysJUnit5Test.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.sleepfordays; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysTest.java b/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysTest.java index c79ee0400..e6decbd27 100644 --- a/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysTest.java +++ b/core/src/test/java/io/temporal/samples/sleepfordays/SleepForDaysTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.sleepfordays; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/core/src/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java b/core/src/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java index e6b3f9320..ab1c01cf0 100644 --- a/core/src/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/terminateworkflow/TerminateWorkflowTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.terminateworkflow; import static org.junit.Assert.*; diff --git a/core/src/test/java/io/temporal/samples/tracing/TracingTest.java b/core/src/test/java/io/temporal/samples/tracing/TracingTest.java index e0baa2b94..303462daa 100644 --- a/core/src/test/java/io/temporal/samples/tracing/TracingTest.java +++ b/core/src/test/java/io/temporal/samples/tracing/TracingTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.tracing; import static org.junit.Assert.*; diff --git a/license-header.txt b/license-header.txt deleted file mode 100644 index cc53a25f9..000000000 --- a/license-header.txt +++ /dev/null @@ -1,16 +0,0 @@ - Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - - Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Modifications copyright (C) 2017 Uber Technologies, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"). You may not - use this file except in compliance with the License. A copy of the License is - located at - - http://aws.amazon.com/apache2.0 - - or in the "license" file accompanying this file. This file is distributed on - an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - express or implied. See the License for the specific language governing - permissions and limitations under the License. diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/SamplesController.java index 79185cd67..bd3b2eb50 100644 --- a/springboot-basic/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import io.temporal.client.WorkflowClient; diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java index 88ca068a1..8edec517f 100644 --- a/springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import org.springframework.boot.SpringApplication; diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java index d727696f0..1e1e027be 100644 --- a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello; import io.temporal.activity.ActivityInterface; diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java index 6dd3a39fe..924d3f237 100644 --- a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello; import io.temporal.samples.springboot.hello.model.Person; diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java index fd1675623..25c0bab87 100644 --- a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello; import io.temporal.samples.springboot.hello.model.Person; diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java index 05336a9f3..2b3a897a4 100644 --- a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello; import io.temporal.activity.ActivityOptions; diff --git a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java index c71862b23..4472fee6b 100644 --- a/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java +++ b/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello.model; public class Person { diff --git a/springboot-basic/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java b/springboot-basic/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java index 1aab3fdc0..5efe43102 100644 --- a/springboot-basic/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java +++ b/springboot-basic/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import io.temporal.client.WorkflowClient; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java index 814236e09..3db4c8ca1 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/SamplesController.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import io.grpc.StatusRuntimeException; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java b/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java index 132464afc..9eed45e85 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import org.springframework.boot.SpringApplication; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/actuator/WorkerActuatorEndpoint.java b/springboot/src/main/java/io/temporal/samples/springboot/actuator/WorkerActuatorEndpoint.java index 140bf2847..cdf6ea71c 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/actuator/WorkerActuatorEndpoint.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/actuator/WorkerActuatorEndpoint.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.actuator; import io.temporal.common.metadata.*; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelConfig.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelConfig.java index febb78464..af926b1ed 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelConfig.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelConfig.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import org.apache.camel.CamelContext; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelResource.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelResource.java index 43cb142e6..86ad47c65 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelResource.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelResource.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import java.util.List; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java index 9bf96dce3..5fe4c4a8f 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/CamelRoutes.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import io.temporal.client.WorkflowClient; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OfficeOrder.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OfficeOrder.java index 82b998a21..bf45baae4 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/OfficeOrder.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OfficeOrder.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import javax.persistence.*; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivity.java index f94d6ecf1..987aa356c 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivity.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import io.temporal.activity.ActivityInterface; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java index 088fdb9f3..f05c79640 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import io.temporal.spring.boot.ActivityImpl; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderRepository.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderRepository.java index 255955112..77bd140d8 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderRepository.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderRepository.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflow.java index 067d92bcf..2ec963b6d 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflow.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import io.temporal.workflow.WorkflowInterface; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflowImpl.java index 60a129e3e..c8f1c458b 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflowImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/camel/OrderWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.camel; import io.temporal.activity.ActivityOptions; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivity.java index 06f9d03aa..01dddadf1 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivity.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.customize; import io.temporal.activity.ActivityInterface; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivityImpl.java index 9d28c8ed9..0f9c3edf6 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivityImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.customize; import io.temporal.spring.boot.ActivityImpl; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflow.java index ffe9574eb..6bfcc4fb6 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflow.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.customize; import io.temporal.workflow.WorkflowInterface; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflowImpl.java index d5b845740..390de4625 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflowImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/CustomizeWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.customize; import io.temporal.activity.ActivityOptions; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java b/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java index 5ce82d019..f7c27f502 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/customize/TemporalOptionsConfig.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.customize; import io.temporal.client.WorkflowClientOptions; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java index d727696f0..1e1e027be 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello; import io.temporal.activity.ActivityInterface; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java index 6dd3a39fe..924d3f237 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello; import io.temporal.samples.springboot.hello.model.Person; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java index fd1675623..25c0bab87 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello; import io.temporal.samples.springboot.hello.model.Person; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java index 05336a9f3..2b3a897a4 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello; import io.temporal.activity.ActivityOptions; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java b/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java index c71862b23..4472fee6b 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/hello/model/Person.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.hello.model; public class Person { diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivity.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivity.java index 9a6933497..7a8d59174 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivity.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.kafka; import io.temporal.activity.ActivityInterface; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java index 81bb6634f..360c3d263 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaActivityImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.kafka; import io.temporal.failure.ApplicationFailure; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaConfig.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaConfig.java index 30b07d1bb..bfaaf3ea8 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaConfig.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/KafkaConfig.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.kafka; import java.io.IOException; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java index 6b84ebd21..4b8d7f415 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageController.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.kafka; import java.util.ArrayList; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflow.java index 866482b71..bc29a15f6 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflow.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.kafka; import io.temporal.workflow.SignalMethod; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflowImpl.java index 8aef1a9c9..88fb0b534 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflowImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/kafka/MessageWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.kafka; import io.temporal.activity.ActivityOptions; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/ProductNotAvailableForAmountException.java b/springboot/src/main/java/io/temporal/samples/springboot/update/ProductNotAvailableForAmountException.java index 56ce54e4a..602295cce 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/ProductNotAvailableForAmountException.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/ProductNotAvailableForAmountException.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update; public class ProductNotAvailableForAmountException extends Exception { diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivities.java b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivities.java index 8be9aa256..27c140345 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivities.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivities.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update; import io.temporal.activity.ActivityInterface; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivitiesImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivitiesImpl.java index 4f0596d59..cb868f7fe 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivitiesImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseActivitiesImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update; import io.temporal.samples.springboot.update.model.Product; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflow.java b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflow.java index d5f086683..92db36d0a 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflow.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflow.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update; import io.temporal.samples.springboot.update.model.Purchase; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflowImpl.java b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflowImpl.java index bc04b3f41..ac62b7172 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflowImpl.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/PurchaseWorkflowImpl.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update; import io.temporal.activity.LocalActivityOptions; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/ResourceNotFoundException.java b/springboot/src/main/java/io/temporal/samples/springboot/update/ResourceNotFoundException.java index 21cfc71ac..448f5c0bf 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/ResourceNotFoundException.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/ResourceNotFoundException.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update; import org.springframework.http.HttpStatus; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/model/Product.java b/springboot/src/main/java/io/temporal/samples/springboot/update/model/Product.java index 74e39b7b3..f4e20830d 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/model/Product.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/model/Product.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update.model; import javax.persistence.*; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/model/ProductRepository.java b/springboot/src/main/java/io/temporal/samples/springboot/update/model/ProductRepository.java index 5d8d2dd99..fec2f75b7 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/model/ProductRepository.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/model/ProductRepository.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update.model; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/springboot/src/main/java/io/temporal/samples/springboot/update/model/Purchase.java b/springboot/src/main/java/io/temporal/samples/springboot/update/model/Purchase.java index 3457c65a4..7cc6d9bc6 100644 --- a/springboot/src/main/java/io/temporal/samples/springboot/update/model/Purchase.java +++ b/springboot/src/main/java/io/temporal/samples/springboot/update/model/Purchase.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot.update.model; public class Purchase { diff --git a/springboot/src/test/java/io/temporal/samples/springboot/CamelSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/CamelSampleTest.java index d751bc426..06d4680ca 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/CamelSampleTest.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/CamelSampleTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import io.temporal.client.WorkflowClient; diff --git a/springboot/src/test/java/io/temporal/samples/springboot/CustomizeSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/CustomizeSampleTest.java index 5e9d82f52..9584f7b13 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/CustomizeSampleTest.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/CustomizeSampleTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import io.temporal.client.WorkflowClient; diff --git a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java index 0fcf65da3..f2019c878 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import io.temporal.client.WorkflowClient; diff --git a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTestMockedActivity.java b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTestMockedActivity.java index 53f62ee0d..eab0c93e8 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTestMockedActivity.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/HelloSampleTestMockedActivity.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import static org.mockito.ArgumentMatchers.any; diff --git a/springboot/src/test/java/io/temporal/samples/springboot/KafkaConsumerTestHelper.java b/springboot/src/test/java/io/temporal/samples/springboot/KafkaConsumerTestHelper.java index 418aab421..1223982be 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/KafkaConsumerTestHelper.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/KafkaConsumerTestHelper.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import java.util.concurrent.CountDownLatch; diff --git a/springboot/src/test/java/io/temporal/samples/springboot/KafkaSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/KafkaSampleTest.java index 97068118e..a1c7a852a 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/KafkaSampleTest.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/KafkaSampleTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import io.temporal.client.WorkflowClient; diff --git a/springboot/src/test/java/io/temporal/samples/springboot/UpdateSampleTest.java b/springboot/src/test/java/io/temporal/samples/springboot/UpdateSampleTest.java index 1552631f6..15fe83beb 100644 --- a/springboot/src/test/java/io/temporal/samples/springboot/UpdateSampleTest.java +++ b/springboot/src/test/java/io/temporal/samples/springboot/UpdateSampleTest.java @@ -1,22 +1,3 @@ -/* - * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved - * - * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Modifications copyright (C) 2017 Uber Technologies, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not - * use this file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - package io.temporal.samples.springboot; import static org.junit.jupiter.api.Assertions.assertThrows; From 2c26d1cf3c0d3199321371471dc2e402ce4fd708 Mon Sep 17 00:00:00 2001 From: Steve Womack Date: Wed, 4 Jun 2025 15:20:04 -0500 Subject: [PATCH 217/240] Adds apikey example (#738) * Adds apikey example --- .gitignore | 3 +- README.md | 2 + .../temporal/samples/apikey/ApiKeyWorker.java | 67 +++++++++++++++ .../temporal/samples/apikey/MyWorkflow.java | 10 +++ .../samples/apikey/MyWorkflowImpl.java | 8 ++ .../java/io/temporal/samples/apikey/README.md | 83 +++++++++++++++++++ .../io/temporal/samples/apikey/Starter.java | 66 +++++++++++++++ 7 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java create mode 100644 core/src/main/java/io/temporal/samples/apikey/MyWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/apikey/MyWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/apikey/README.md create mode 100644 core/src/main/java/io/temporal/samples/apikey/Starter.java diff --git a/.gitignore b/.gitignore index 87bc9f8e1..a560c2465 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ target .classpath .project .settings/ -bin/ \ No newline at end of file +bin/ +core/.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index d3808da94..b04d1f31e 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Configure WorkflowClient to use mTLS**](/core/src/main/java/io/temporal/samples/ssl): Demonstrates how to configure WorkflowClient when using mTLS. +- [**Configure WorkflowClient to use API Key**](/core/src/main/java/io/temporal/samples/apikey): Demonstrates how to configure WorkflowClient when using API Keys. + - [**Payload Codec**](/core/src/main/java/io/temporal/samples/encodefailures): Demonstrates how to use simple codec to encode/decode failure messages. - [**Exclude Workflow/ActivityTypes from Interceptors**](/core/src/main/java/io/temporal/samples/excludefrominterceptor): Demonstrates how to exclude certain workflow / activity types from interceptors. diff --git a/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java b/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java new file mode 100644 index 000000000..7425b88d6 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java @@ -0,0 +1,67 @@ +package io.temporal.samples.apikey; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class ApiKeyWorker { + static final String TASK_QUEUE = "MyTaskQueue"; + + public static void main(String[] args) throws Exception { + // For temporal cloud this would be ${cloud-region}.{cloud}.api.temporal.io:7233 + // Example us-east-1.aws.api.temporal.io:7233 + String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT"); + // Your registered namespace. + String namespace = System.getenv("TEMPORAL_NAMESPACE"); + // Your API Key + String apiKey = System.getenv("TEMPORAL_API_KEY"); + + if (targetEndpoint == null || namespace == null || apiKey == null) { + throw new IllegalArgumentException( + "TEMPORAL_ENDPOINT, TEMPORAL_NAMESPACE, and TEMPORAL_API_KEY environment variables must be set"); + } + + // Create API Key enabled client + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs( + WorkflowServiceStubsOptions.newBuilder() + .setTarget(targetEndpoint) + .setEnableHttps(true) + .addApiKey(() -> apiKey) + .build()); + + // Now setup and start workflow worker + WorkflowClient client = + WorkflowClient.newInstance( + service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build()); + + // worker factory that can be used to create workers for specific task queues + WorkerFactory factory = WorkerFactory.newInstance(client); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register our workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + System.out.println("Worker started. Press Ctrl+C to exit."); + // Keep the worker running + Thread.currentThread().join(); + } +} diff --git a/core/src/main/java/io/temporal/samples/apikey/MyWorkflow.java b/core/src/main/java/io/temporal/samples/apikey/MyWorkflow.java new file mode 100644 index 000000000..d02953d73 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/apikey/MyWorkflow.java @@ -0,0 +1,10 @@ +package io.temporal.samples.apikey; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface MyWorkflow { + @WorkflowMethod + String execute(); +} diff --git a/core/src/main/java/io/temporal/samples/apikey/MyWorkflowImpl.java b/core/src/main/java/io/temporal/samples/apikey/MyWorkflowImpl.java new file mode 100644 index 000000000..f6fea0fe7 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/apikey/MyWorkflowImpl.java @@ -0,0 +1,8 @@ +package io.temporal.samples.apikey; + +public class MyWorkflowImpl implements MyWorkflow { + @Override + public String execute() { + return "done"; + } +} diff --git a/core/src/main/java/io/temporal/samples/apikey/README.md b/core/src/main/java/io/temporal/samples/apikey/README.md new file mode 100644 index 000000000..494aa0458 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/apikey/README.md @@ -0,0 +1,83 @@ +# Workflow execution with API Key + +This example shows how to secure your Temporal application with API Key authentication. +This is required to connect with Temporal Cloud or any production Temporal deployment that uses API Key authentication. + +## Prerequisites + +1. A Temporal Cloud account +2. A namespace in Temporal Cloud +3. An API Key for your namespace + +## Getting your API Key + +1. Log in to your Temporal Cloud account +2. Navigate to your namespace +3. Go to Namespace Settings > API Keys +4. Click "Create API Key" +5. Give your API Key a name and select the appropriate permissions +6. Copy the API Key value (you won't be able to see it again) + +## Export env variables + +Before running the example you need to export the following env variables: + +```bash +# Your Temporal Cloud endpoint (e.g., us-east-1.aws.api.temporal.io:7233) +export TEMPORAL_ENDPOINT="us-east-1.aws.api.temporal.io:7233" + +# Your Temporal Cloud namespace +export TEMPORAL_NAMESPACE="your-namespace" + +# Your API Key from Temporal Cloud +export TEMPORAL_API_KEY="your-api-key" +``` + +## Running this sample + +This sample consists of two components that need to be run in separate terminals: + +1. First, start the worker: +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.apikey.ApiKeyWorker +``` + +2. Then, in a new terminal, run the starter: +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.apikey.Starter +``` + +## Expected result + +When running the worker, you should see: +```text +[main] INFO i.t.s.WorkflowServiceStubsImpl - Created WorkflowServiceStubs for channel: ManagedChannelOrphanWrapper{delegate=ManagedChannelImpl{logId=1, target=us-east-1.aws.api.temporal.io:7233}} +[main] INFO io.temporal.internal.worker.Poller - start: Poller{name=Workflow Poller taskQueue="MyTaskQueue", namespace="your-namespace"} +Worker started. Press Ctrl+C to exit. +``` + +When running the starter, you should see: +```text +[main] INFO i.t.s.WorkflowServiceStubsImpl - Created WorkflowServiceStubs for channel: ManagedChannelOrphanWrapper{delegate=ManagedChannelImpl{logId=1, target=us-east-1.aws.api.temporal.io:7233}} +[main] INFO io.temporal.internal.worker.Poller - start: Poller{name=Workflow Poller taskQueue="MyTaskQueue", namespace="your-namespace"} +done +``` + +## Troubleshooting + +If you encounter any issues: + +1. Verify your environment variables are set correctly: + ```bash + echo $TEMPORAL_ENDPOINT + echo $TEMPORAL_NAMESPACE + echo $TEMPORAL_API_KEY + ``` + +2. Check that your API Key has the correct permissions for your namespace + +3. Ensure your namespace is active and accessible + +4. If you get connection errors, verify your endpoint is correct and accessible from your network + +5. Make sure you're running the commands from the correct directory (where the `gradlew` script is located) diff --git a/core/src/main/java/io/temporal/samples/apikey/Starter.java b/core/src/main/java/io/temporal/samples/apikey/Starter.java new file mode 100644 index 000000000..60afe7c21 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/apikey/Starter.java @@ -0,0 +1,66 @@ +package io.temporal.samples.apikey; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class Starter { + + static final String TASK_QUEUE = "MyTaskQueue"; + static final String WORKFLOW_ID = "HelloAPIKeyWorkflow"; + + public static void main(String[] args) throws Exception { + // For temporal cloud this would be ${cloud-region}.{cloud}.api.temporal.io:7233 + // Example us-east-1.aws.api.temporal.io:7233 + String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT"); + // Your registered namespace. + String namespace = System.getenv("TEMPORAL_NAMESPACE"); + // Your API Key + String apiKey = System.getenv("TEMPORAL_API_KEY"); + + if (targetEndpoint == null || namespace == null || apiKey == null) { + throw new IllegalArgumentException( + "TEMPORAL_ENDPOINT, TEMPORAL_NAMESPACE, and TEMPORAL_API_KEY environment variables must be set"); + } + + // Create API Key enabled client + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs( + WorkflowServiceStubsOptions.newBuilder() + .setTarget(targetEndpoint) + .setEnableHttps(true) + .addApiKey(() -> apiKey) + .build()); + + WorkflowClient client = + WorkflowClient.newInstance( + service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build()); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(TASK_QUEUE); + + worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); + + factory.start(); + + // Create the workflow client stub. It is used to start our workflow execution. + MyWorkflow workflow = + client.newWorkflowStub( + MyWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + String greeting = workflow.execute(); + + // Display workflow execution results + System.out.println(greeting); + System.exit(0); + } +} From c4217c9ce2a3a2e3567d714f4a28cc2ee8dc2048 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Mon, 9 Jun 2025 10:34:01 -0400 Subject: [PATCH 218/240] Convert service description to markdown (#740) --- .../io/temporal/samples/nexus/service/description.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/nexus/service/description.md b/core/src/main/java/io/temporal/samples/nexus/service/description.md index 98dc27083..d79e151cd 100644 --- a/core/src/main/java/io/temporal/samples/nexus/service/description.md +++ b/core/src/main/java/io/temporal/samples/nexus/service/description.md @@ -1,8 +1,6 @@ -Service Name: -NexusService -Operation Names: -echo -hello +## Service: [NexusService](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java) + - operation: `echo` + - operation: `hello` + +See https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java for Input / Output types. -Input / Output arguments are in the following repository: -https://github.com/temporalio/samples-java/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java From 62a35cee86ce873f8f9fcdd424e3dd50d17bc60c Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Fri, 20 Jun 2025 16:16:44 -0700 Subject: [PATCH 219/240] Show mapping Nexus operation to multiple input args (#744) Show mapping Nexus operation to multiple input args --- README.md | 2 + .../samples/nexusmultipleargs/README.MD | 36 +++++++++++ .../caller/CallerStarter.java | 39 ++++++++++++ .../caller/CallerWorker.java | 32 ++++++++++ .../caller/EchoCallerWorkflow.java | 10 ++++ .../caller/EchoCallerWorkflowImpl.java | 25 ++++++++ .../caller/HelloCallerWorkflow.java | 11 ++++ .../caller/HelloCallerWorkflowImpl.java | 32 ++++++++++ .../handler/HandlerWorker.java | 22 +++++++ .../handler/HelloHandlerWorkflow.java | 11 ++++ .../handler/HelloHandlerWorkflowImpl.java | 24 ++++++++ .../handler/NexusServiceImpl.java | 60 +++++++++++++++++++ 12 files changed, 304 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/README.MD create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java diff --git a/README.md b/README.md index b04d1f31e..a8af530f4 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Getting Started**](/core/src/main/java/io/temporal/samples/nexus): Demonstrates how to get started with Temporal and Nexus. +- [**Mapping Multiple Arguments**](/core/src/main/java/io/temporal/samples/nexus): Demonstrates how map a Nexus operation to a Workflow that takes multiple arguments. + - [**Cancellation**](/core/src/main/java/io/temporal/samples/nexuscancellation): Demonstrates how to cancel an async Nexus operation. - [**Context/Header Propagation**](/core/src/main/java/io/temporal/samples/nexuscontextpropagation): Demonstrates how to propagate context through Nexus operation headers. diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/README.MD b/core/src/main/java/io/temporal/samples/nexusmultipleargs/README.MD new file mode 100644 index 000000000..754545091 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/README.MD @@ -0,0 +1,36 @@ +# Nexus Multiple Arguments Sample + +This sample shows how to map a Nexus operation to a caller workflow that takes multiple input arguments using [WorkflowRunOperation.fromWorkflowHandle](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/nexus/WorkflowRunOperation.html#fromWorkflowHandle(io.temporal.nexus.WorkflowHandleFactory)). + +To run this sample, set up your environment following the instructions in the main [Nexus Sample](../nexus/README.md). + +In separate terminal windows: + +### Nexus handler worker + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexusmultipleargs.handler.HandlerWorker \ + --args="-target-host localhost:7233 -namespace my-target-namespace" +``` + +### Nexus caller worker + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexusmultipleargs.caller.CallerWorker \ + --args="-target-host localhost:7233 -namespace my-caller-namespace" +``` + +### Start caller workflow + +``` +./gradlew -q execute -PmainClass=io.temporal.samples.nexusmultipleargs.caller.CallerStarter \ + --args="-target-host localhost:7233 -namespace my-caller-namespace" +``` + +### Output + +which should result in: +``` +[main] INFO i.t.s.nexus.caller.CallerStarter - Workflow result: Nexus Echo πŸ‘‹ +[main] INFO i.t.s.nexus.caller.CallerStarter - Workflow result: Β‘Hola! Nexus πŸ‘‹ +``` diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java new file mode 100644 index 000000000..beebdf406 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java @@ -0,0 +1,39 @@ +package io.temporal.samples.nexusmultipleargs.caller; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.nexus.caller.CallerWorker; +import io.temporal.samples.nexus.caller.EchoCallerWorkflow; +import io.temporal.samples.nexus.caller.HelloCallerWorkflow; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.samples.nexus.service.NexusService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CallerStarter { + private static final Logger logger = LoggerFactory.getLogger(CallerStarter.class); + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setTaskQueue(CallerWorker.DEFAULT_TASK_QUEUE_NAME).build(); + EchoCallerWorkflow echoWorkflow = + client.newWorkflowStub(EchoCallerWorkflow.class, workflowOptions); + WorkflowExecution execution = WorkflowClient.start(echoWorkflow::echo, "Nexus Echo πŸ‘‹"); + logger.info( + "Started EchoCallerWorkflow workflowId: {} runId: {}", + execution.getWorkflowId(), + execution.getRunId()); + logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); + HelloCallerWorkflow helloWorkflow = + client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); + logger.info( + "Started HelloCallerWorkflow workflowId: {} runId: {}", + execution.getWorkflowId(), + execution.getRunId()); + logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java new file mode 100644 index 000000000..1db03a677 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java @@ -0,0 +1,32 @@ +package io.temporal.samples.nexusmultipleargs.caller; + +import io.temporal.client.WorkflowClient; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.NexusServiceOptions; +import java.util.Collections; + +public class CallerWorker { + public static final String DEFAULT_TASK_QUEUE_NAME = "my-caller-workflow-task-queue"; + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); + worker.registerWorkflowImplementationTypes( + WorkflowImplementationOptions.newBuilder() + .setNexusServiceOptions( + Collections.singletonMap( + "NexusService", + NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) + .build(), + EchoCallerWorkflowImpl.class, + HelloCallerWorkflowImpl.class); + + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflow.java new file mode 100644 index 000000000..47f1adce2 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflow.java @@ -0,0 +1,10 @@ +package io.temporal.samples.nexusmultipleargs.caller; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface EchoCallerWorkflow { + @WorkflowMethod + String echo(String message); +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java new file mode 100644 index 000000000..ea9aaabb0 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java @@ -0,0 +1,25 @@ +package io.temporal.samples.nexusmultipleargs.caller; + +import io.temporal.samples.nexus.caller.EchoCallerWorkflow; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.NexusOperationOptions; +import io.temporal.workflow.NexusServiceOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { + NexusService nexusService = + Workflow.newNexusServiceStub( + NexusService.class, + NexusServiceOptions.newBuilder() + .setOperationOptions( + NexusOperationOptions.newBuilder() + .setScheduleToCloseTimeout(Duration.ofSeconds(10)) + .build()) + .build()); + + @Override + public String echo(String message) { + return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java new file mode 100644 index 000000000..aeb7a13db --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java @@ -0,0 +1,11 @@ +package io.temporal.samples.nexusmultipleargs.caller; + +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloCallerWorkflow { + @WorkflowMethod + String hello(String message, NexusService.Language language); +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java new file mode 100644 index 000000000..94f4c3fc5 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java @@ -0,0 +1,32 @@ +package io.temporal.samples.nexusmultipleargs.caller; + +import io.temporal.samples.nexus.caller.HelloCallerWorkflow; +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.NexusOperationHandle; +import io.temporal.workflow.NexusOperationOptions; +import io.temporal.workflow.NexusServiceOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { + NexusService nexusService = + Workflow.newNexusServiceStub( + NexusService.class, + NexusServiceOptions.newBuilder() + .setOperationOptions( + NexusOperationOptions.newBuilder() + .setScheduleToCloseTimeout(Duration.ofSeconds(10)) + .build()) + .build()); + + @Override + public String hello(String message, NexusService.Language language) { + NexusOperationHandle handle = + Workflow.startNexusOperation( + nexusService::hello, new NexusService.HelloInput(message, language)); + // Optionally wait for the operation to be started. NexusOperationExecution will contain the + // operation token in case this operation is asynchronous. + handle.getExecution().get(); + return handle.getResult().get().getMessage(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java new file mode 100644 index 000000000..0ec77889c --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java @@ -0,0 +1,22 @@ +package io.temporal.samples.nexusmultipleargs.handler; + +import io.temporal.client.WorkflowClient; +import io.temporal.samples.nexus.options.ClientOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class HandlerWorker { + public static final String DEFAULT_TASK_QUEUE_NAME = "my-handler-task-queue"; + + public static void main(String[] args) { + WorkflowClient client = ClientOptions.getWorkflowClient(args); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); + worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); + worker.registerNexusServiceImplementation(new NexusServiceImpl()); + + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java new file mode 100644 index 000000000..0a443d468 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java @@ -0,0 +1,11 @@ +package io.temporal.samples.nexusmultipleargs.handler; + +import io.temporal.samples.nexus.service.NexusService; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloHandlerWorkflow { + @WorkflowMethod + NexusService.HelloOutput hello(String name, NexusService.Language language); +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java new file mode 100644 index 000000000..b802cee34 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java @@ -0,0 +1,24 @@ +package io.temporal.samples.nexusmultipleargs.handler; + +import io.temporal.failure.ApplicationFailure; +import io.temporal.samples.nexus.service.NexusService; + +public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { + @Override + public NexusService.HelloOutput hello(String name, NexusService.Language language) { + switch (language) { + case EN: + return new NexusService.HelloOutput("Hello " + name + " πŸ‘‹"); + case FR: + return new NexusService.HelloOutput("Bonjour " + name + " πŸ‘‹"); + case DE: + return new NexusService.HelloOutput("Hallo " + name + " πŸ‘‹"); + case ES: + return new NexusService.HelloOutput("Β‘Hola! " + name + " πŸ‘‹"); + case TR: + return new NexusService.HelloOutput("Merhaba " + name + " πŸ‘‹"); + } + throw ApplicationFailure.newFailure( + "Unsupported language: " + language, "UNSUPPORTED_LANGUAGE"); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java new file mode 100644 index 000000000..20d55fed8 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java @@ -0,0 +1,60 @@ +package io.temporal.samples.nexusmultipleargs.handler; + +import io.nexusrpc.handler.OperationHandler; +import io.nexusrpc.handler.OperationImpl; +import io.nexusrpc.handler.ServiceImpl; +import io.temporal.client.WorkflowOptions; +import io.temporal.nexus.Nexus; +import io.temporal.nexus.WorkflowHandle; +import io.temporal.nexus.WorkflowRunOperation; +import io.temporal.samples.nexus.service.NexusService; + +// To create a service implementation, annotate the class with @ServiceImpl and provide the +// interface that the service implements. The service implementation class should have methods that +// return OperationHandler that correspond to the operations defined in the service interface. +@ServiceImpl(service = NexusService.class) +public class NexusServiceImpl { + @OperationImpl + public OperationHandler echo() { + // OperationHandler.sync is a meant for exposing simple RPC handlers. + return OperationHandler.sync( + // The method is for making arbitrary short calls to other services or databases, or + // perform simple computations such as this one. Users can also access a workflow client by + // calling + // Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as + // signaling, querying, or listing workflows. + (ctx, details, input) -> new NexusService.EchoOutput(input.getMessage())); + } + + @OperationImpl + public OperationHandler hello() { + // If the operation input parameters are different from the workflow input parameters, + // use the WorkflowRunOperation.fromWorkflowHandler constructor and the appropriate constructor + // method on WorkflowHandle to map the Nexus input to the workflow parameters. + return WorkflowRunOperation.fromWorkflowHandle( + (ctx, details, input) -> + WorkflowHandle.fromWorkflowMethod( + Nexus.getOperationContext() + .getWorkflowClient() + .newWorkflowStub( + HelloHandlerWorkflow.class, + // Workflow IDs should typically be business meaningful IDs and are used + // to + // dedupe workflow starts. + // For this example, we're using the request ID allocated by Temporal + // when + // the + // caller workflow schedules + // the operation, this ID is guaranteed to be stable across retries of + // this + // operation. + // + // Task queue defaults to the task queue this operation is handled on. + WorkflowOptions.newBuilder() + .setWorkflowId(details.getRequestId()) + .build()) + ::hello, + input.getName(), + input.getLanguage())); + } +} From a650078f4d7586e1ebe26e5c7dadd6e09a225a8d Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 24 Jun 2025 16:45:41 -0700 Subject: [PATCH 220/240] Switch poller sample to use ApplicationErrorCategory (#743) Switch poller sample to use ApplicationErrorCategory --- build.gradle | 2 +- .../InfrequentPollingActivityImpl.java | 13 ++++++++++--- ...quentPollingWithRetryAfterActivityImpl.java | 18 +++++++++++------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index a833ff3cd..6c5da619d 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.28.1' + javaSDKVersion = '1.30.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java index 5b9a5b0cd..1bca960a9 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java @@ -1,11 +1,12 @@ package io.temporal.samples.polling.infrequent; -import io.temporal.activity.Activity; +import io.temporal.failure.ApplicationErrorCategory; +import io.temporal.failure.ApplicationFailure; import io.temporal.samples.polling.PollingActivities; import io.temporal.samples.polling.TestService; public class InfrequentPollingActivityImpl implements PollingActivities { - private TestService service; + private final TestService service; public InfrequentPollingActivityImpl(TestService service) { this.service = service; @@ -17,7 +18,13 @@ public String doPoll() { return service.getServiceResult(); } catch (TestService.TestServiceException e) { // We want to rethrow the service exception so we can poll via activity retries - throw Activity.wrap(e); + throw ApplicationFailure.newBuilder() + .setMessage(e.getMessage()) + .setType(e.getClass().getName()) + .setCause(e) + // This failure is expected so we set it as benign to avoid excessive logging + .setCategory(ApplicationErrorCategory.BENIGN) + .build(); } } } diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java index a202e0b71..2de6a7731 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterActivityImpl.java @@ -1,6 +1,7 @@ package io.temporal.samples.polling.infrequentwithretryafter; import io.temporal.activity.Activity; +import io.temporal.failure.ApplicationErrorCategory; import io.temporal.failure.ApplicationFailure; import io.temporal.samples.polling.PollingActivities; import io.temporal.samples.polling.TestService; @@ -10,7 +11,7 @@ import java.time.format.DateTimeFormatter; public class InfrequentPollingWithRetryAfterActivityImpl implements PollingActivities { - private TestService service; + private final TestService service; final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME; public InfrequentPollingWithRetryAfterActivityImpl(TestService service) { @@ -32,13 +33,16 @@ public String doPoll() { // which is the test service exception // and delay which is the interval to next retry based on test service retry-after directive System.out.println("Activity next retry in: " + e.getRetryAfterInMinutes() + " minutes"); - throw ApplicationFailure.newFailureWithCauseAndDelay( - e.getMessage(), - e.getClass().getName(), - e, - // here we set the next retry interval based on Retry-After duration given to us by our + throw ApplicationFailure.newBuilder() + .setMessage(e.getMessage()) + .setType(e.getClass().getName()) + .setCause(e) + // Here we set the next retry interval based on Retry-After duration given to us by our // service - Duration.ofMinutes(e.getRetryAfterInMinutes())); + .setNextRetryDelay(Duration.ofMinutes(e.getRetryAfterInMinutes())) + // This failure is expected so we set it as benign to avoid excessive logging + .setCategory(ApplicationErrorCategory.BENIGN) + .build(); } } } From daaf8c4759b795790fa7c072fae8173b0463bc24 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 24 Jun 2025 17:01:49 -0700 Subject: [PATCH 221/240] Add CancellationType to nexus cancellation sample (#741) Add CancellationType to nexus cancellation sample --- .../samples/nexuscancellation/README.MD | 19 +++++++-- .../caller/HelloCallerWorkflowImpl.java | 12 +++++- .../handler/HelloHandlerWorkflowImpl.java | 41 ++++++++++++------- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD b/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD index f4da82852..bd69da875 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD @@ -1,6 +1,6 @@ # Nexus Cancellation -This sample shows how to cancel a Nexus operation from a caller workflow. +This sample shows how to cancel a Nexus operation from a caller workflow and specify a cancellation type. In this sample we will show using the `WAIT_REQUESTED` cancellation type, which allows the caller to return after the handler workflow has received the requested to be cancelled, but does not wait for the handler workflow to finish processing the cancellation request. To run this sample, set up your environment following the instructions in the main [Nexus Sample](../nexus/README.md). @@ -29,8 +29,19 @@ Next, in separate terminal windows: ### Output -which should result in: +which should result in on the caller side: ``` -INFO i.t.s.n.caller.CallerStarter - Started workflow workflowId: 326732dd-a2b1-4de7-9ddd-dcee4f9f0229 runId: d580499f-79d5-461d-bd49-6248b4e522ae -INFO i.t.s.n.caller.CallerStarter - Workflow result: Hallo Nexus πŸ‘‹ +14:33:52.810 i.t.s.n.caller.CallerStarter - Started workflow workflowId: 87e97bf0-ca8a-4ae6-a9dc-ae97e5c0ac41 runId: 01976b36-a524-71a1-b848-8eb385fec2c3 +14:33:54.250 i.t.s.n.caller.CallerStarter - Workflow result: Hallo Nexus πŸ‘‹ ``` + +on the handler side: + +``` +14:33:54.177 INFO i.t.s.n.h.HelloHandlerWorkflowImpl - HelloHandlerWorkflow was cancelled successfully. +14:33:56.167 INFO i.t.s.n.h.HelloHandlerWorkflowImpl - HelloHandlerWorkflow was cancelled successfully. +14:33:57.172 INFO i.t.s.n.h.HelloHandlerWorkflowImpl - HelloHandlerWorkflow was cancelled successfully. +14:33:57.176 INFO i.t.s.n.h.HelloHandlerWorkflowImpl - HelloHandlerWorkflow was cancelled successfully. +``` + +Notice the timing, the caller workflow returned before the handler workflow was cancelled. This is because of the use of `WAIT_REQUESTED` as the cancellation type in the Nexus operation. This means the caller didn't have to wait for the handler workflow to finish, but still guarantees the handler workflow will receive the cancellation request. \ No newline at end of file diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java index c3dc6440c..1bea801c8 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java @@ -22,6 +22,12 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { .setOperationOptions( NexusOperationOptions.newBuilder() .setScheduleToCloseTimeout(Duration.ofSeconds(10)) + // Set the cancellation type to WAIT_REQUESTED. This means that the caller + // will wait for the cancellation request to be received by the handler before + // proceeding with the cancellation. + // + // By default, the caller would wait until the operation is completed. + .setCancellationType(NexusOperationCancellationType.WAIT_REQUESTED) .build()) .build()); @@ -55,10 +61,12 @@ public String hello(String message) { // Trigger cancellation of all uncompleted nexus operations invocations within the cancellation // scope scope.cancel(); - // Optionally, wait for all nexus operations to complete + // Wait for all nexus operations to receive a cancellation request before + // proceeding. // // Note: Once the workflow completes any pending cancellation requests are dropped by the - // server. + // server. In general, it is a good practice to wait for all cancellation requests to be + // processed before completing the workflow. for (Promise promise : results) { try { promise.get(); diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java index 406b4b20b..ca6510f60 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java @@ -1,29 +1,42 @@ package io.temporal.samples.nexuscancellation.handler; import io.temporal.failure.ApplicationFailure; +import io.temporal.failure.CanceledFailure; import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; import io.temporal.samples.nexus.service.NexusService; import io.temporal.workflow.Workflow; import java.time.Duration; +import org.slf4j.Logger; public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { + public static final Logger log = Workflow.getLogger(HelloHandlerWorkflowImpl.class); + @Override public NexusService.HelloOutput hello(NexusService.HelloInput input) { // Sleep for a random duration to simulate some work - Workflow.sleep(Duration.ofSeconds(Workflow.newRandom().nextInt(5))); - switch (input.getLanguage()) { - case EN: - return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); - case FR: - return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); - case DE: - return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); - case ES: - return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); - case TR: - return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + try { + Workflow.sleep(Duration.ofSeconds(Workflow.newRandom().nextInt(5))); + switch (input.getLanguage()) { + case EN: + return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + case FR: + return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + case DE: + return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + case ES: + return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + case TR: + return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + } + throw ApplicationFailure.newFailure( + "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); + } catch (CanceledFailure e) { + // Simulate some work after cancellation is requested + Workflow.newDetachedCancellationScope( + () -> Workflow.sleep(Duration.ofSeconds(Workflow.newRandom().nextInt(5)))) + .run(); + log.info("HelloHandlerWorkflow was cancelled successfully."); + throw e; } - throw ApplicationFailure.newFailure( - "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); } } From 38372fa407b5e0dca0a69537ee2416949c5d1f7a Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Thu, 26 Jun 2025 09:21:10 -0700 Subject: [PATCH 222/240] Add custom annotation sample (#734) Add custom annotation sample --- README.md | 2 + build.gradle | 2 +- .../BenignExceptionTypes.java | 18 ++ ...gnExceptionTypesAnnotationInterceptor.java | 113 ++++++++++ .../customannotation/CustomAnnotation.java | 197 ++++++++++++++++++ .../samples/customannotation/README.md | 9 + 6 files changed, 340 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypes.java create mode 100644 core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypesAnnotationInterceptor.java create mode 100644 core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java create mode 100644 core/src/main/java/io/temporal/samples/customannotation/README.md diff --git a/README.md b/README.md index a8af530f4..f6351bbce 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Safe Message Passing**](/core/src/main/java/io/temporal/samples/safemessagepassing): Safely handling concurrent updates and signals messages. +- [**Custom Annotation**](/core/src/main/java/io/temporal/samples/customannotation): Demonstrates how to create a custom annotation using an interceptor. + #### API demonstrations - [**Async Untyped Child Workflow**](/core/src/main/java/io/temporal/samples/asyncuntypedchild): Demonstrates how to invoke an untyped child workflow async, that can complete after parent workflow is already completed. diff --git a/build.gradle b/build.gradle index 6c5da619d..a7ece2dce 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.30.0' + javaSDKVersion = '1.30.1' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypes.java b/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypes.java new file mode 100644 index 000000000..a97ebd26c --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypes.java @@ -0,0 +1,18 @@ +package io.temporal.samples.customannotation; + +import java.lang.annotation.*; + +/** + * BenignExceptionTypes is an annotation that can be used to specify an exception type is benign and + * not an issue worth logging. + * + *

For this annotation to work, {@link BenignExceptionTypesAnnotationInterceptor} must be passed + * as a worker interceptor to the worker factory. + */ +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface BenignExceptionTypes { + /** Type of exceptions that should be considered benign and not logged as errors. */ + Class[] value(); +} diff --git a/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypesAnnotationInterceptor.java b/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypesAnnotationInterceptor.java new file mode 100644 index 000000000..71ee51a9d --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypesAnnotationInterceptor.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.customannotation; + +import io.temporal.activity.ActivityExecutionContext; +import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; +import io.temporal.common.interceptors.WorkerInterceptorBase; +import io.temporal.common.metadata.POJOActivityImplMetadata; +import io.temporal.common.metadata.POJOActivityMethodMetadata; +import io.temporal.failure.ApplicationErrorCategory; +import io.temporal.failure.ApplicationFailure; +import io.temporal.failure.TemporalFailure; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Checks if the activity method has the {@link BenignExceptionTypes} annotation. If it does, it + * will throw an ApplicationFailure with {@link ApplicationErrorCategory#BENIGN}. + */ +public class BenignExceptionTypesAnnotationInterceptor extends WorkerInterceptorBase { + + @Override + public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) { + return new ActivityInboundCallsInterceptorAnnotation(next); + } + + public static class ActivityInboundCallsInterceptorAnnotation + extends io.temporal.common.interceptors.ActivityInboundCallsInterceptorBase { + private final ActivityInboundCallsInterceptor next; + private Set> benignExceptionTypes = new HashSet<>(); + + public ActivityInboundCallsInterceptorAnnotation(ActivityInboundCallsInterceptor next) { + super(next); + this.next = next; + } + + @Override + public void init(ActivityExecutionContext context) { + List activityMethods = + POJOActivityImplMetadata.newInstance(context.getInstance().getClass()) + .getActivityMethods(); + POJOActivityMethodMetadata currentActivityMethod = + activityMethods.stream() + .filter(x -> x.getActivityTypeName().equals(context.getInfo().getActivityType())) + .findFirst() + .get(); + // Get the implementation method from the interface method + Method implementationMethod; + try { + implementationMethod = + context + .getInstance() + .getClass() + .getMethod( + currentActivityMethod.getMethod().getName(), + currentActivityMethod.getMethod().getParameterTypes()); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + // Get the @BenignExceptionTypes annotations from the implementation method + BenignExceptionTypes an = implementationMethod.getAnnotation(BenignExceptionTypes.class); + if (an != null && an.value() != null) { + benignExceptionTypes = new HashSet<>(Arrays.asList(an.value())); + } + next.init(context); + } + + @Override + public ActivityOutput execute(ActivityInput input) { + if (benignExceptionTypes.isEmpty()) { + return next.execute(input); + } + try { + return next.execute(input); + } catch (TemporalFailure tf) { + throw tf; + } catch (Exception e) { + if (benignExceptionTypes.contains(e.getClass())) { + // If the exception is in the list of benign exceptions, throw an ApplicationFailure + // with a BENIGN category + throw ApplicationFailure.newBuilder() + .setMessage(e.getMessage()) + .setType(e.getClass().getName()) + .setCause(e) + .setCategory(ApplicationErrorCategory.BENIGN) + .build(); + } + // If the exception is not in the list of benign exceptions, rethrow it + throw e; + } + } + } +} diff --git a/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java b/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java new file mode 100644 index 000000000..9f9fc667d --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.customannotation; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; +import io.temporal.activity.ActivityOptions; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.time.Duration; + +public class CustomAnnotation { + + // Define the task queue name + static final String TASK_QUEUE = "CustomAnnotationTaskQueue"; + + // Define our workflow unique id + static final String WORKFLOW_ID = "CustomAnnotationWorkflow"; + + /** + * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod. + * + *

Workflow Definitions should not contain any heavyweight computations, non-deterministic + * code, network calls, database operations, etc. Those things should be handled by the + * Activities. + * + * @see WorkflowInterface + * @see WorkflowMethod + */ + @WorkflowInterface + public interface GreetingWorkflow { + + /** + * This is the method that is executed when the Workflow Execution is started. The Workflow + * Execution completes when this method finishes execution. + */ + @WorkflowMethod + String getGreeting(String name); + } + + /** + * This is the Activity Definition's Interface. Activities are building blocks of any Temporal + * Workflow and contain any business logic that could perform long running computation, network + * calls, etc. + * + *

Annotating Activity Definition methods with @ActivityMethod is optional. + * + * @see ActivityInterface + * @see ActivityMethod + */ + @ActivityInterface + public interface GreetingActivities { + + /** Define your activity method which can be called during workflow execution */ + String composeGreeting(String greeting, String name); + } + + // Define the workflow implementation which implements our getGreeting workflow method. + public static class GreetingWorkflowImpl implements GreetingWorkflow { + + /** + * Define the GreetingActivities stub. Activity stubs are proxies for activity invocations that + * are executed outside of the workflow thread on the activity worker, that can be on a + * different host. Temporal is going to dispatch the activity results back to the workflow and + * unblock the stub as soon as activity is completed on the activity worker. + */ + private final GreetingActivities activities = + Workflow.newActivityStub( + GreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build()); + + @Override + public String getGreeting(String name) { + // This is a blocking call that returns only after activity is completed. + return activities.composeGreeting("Hello", name); + } + } + + /** + * Implementation of our workflow activity interface. It overwrites our defined composeGreeting + * activity method. + */ + static class GreetingActivitiesImpl implements GreetingActivities { + private int callCount; + + /** + * Our activity implementation simulates a failure 3 times. Given our previously set + * RetryOptions, our workflow is going to retry our activity execution. + */ + @Override + @BenignExceptionTypes({IllegalStateException.class}) + public synchronized String composeGreeting(String greeting, String name) { + if (++callCount < 4) { + System.out.println("composeGreeting activity is going to fail"); + throw new IllegalStateException("not yet"); + } + + // after 3 unsuccessful retries we finally can complete our activity execution + System.out.println("composeGreeting activity is going to complete"); + return greeting + " " + name + "!"; + } + } + + /** + * With our Workflow and Activities defined, we can now start execution. The main method starts + * the worker and then the workflow. + */ + public static void main(String[] args) { + + // Get a Workflow service stub. + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + + /* + * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. + */ + WorkflowClient client = WorkflowClient.newInstance(service); + + /* + * Define the workflow factory. It is used to create workflow workers for a specific task queue. + */ + WorkerFactory factory = + WorkerFactory.newInstance( + client, + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors(new BenignExceptionTypesAnnotationInterceptor()) + .build()); + + /* + * Define the workflow worker. Workflow workers listen to a defined task queue and process + * workflows and activities. + */ + Worker worker = factory.newWorker(TASK_QUEUE); + + /* + * Register our workflow implementation with the worker. + * Workflow implementations must be known to the worker at runtime in + * order to dispatch workflow tasks. + */ + worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); + + /* + * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe, + * the Activity Type is a shared instance. + */ + worker.registerActivitiesImplementations(new GreetingActivitiesImpl()); + + /* + * Start all the workers registered for a specific task queue. + * The started workers then start polling for workflows and activities. + */ + factory.start(); + + // Set our workflow options + WorkflowOptions workflowOptions = + WorkflowOptions.newBuilder().setWorkflowId(WORKFLOW_ID).setTaskQueue(TASK_QUEUE).build(); + + // Create the workflow client stub. It is used to start our workflow execution. + GreetingWorkflow workflow = client.newWorkflowStub(GreetingWorkflow.class, workflowOptions); + + /* + * Execute our workflow and wait for it to complete. The call to our getGreeting method is + * synchronous. + * + * See {@link io.temporal.samples.hello.HelloSignal} for an example of starting workflow + * without waiting synchronously for its result. + */ + String greeting = workflow.getGreeting("World"); + + // Display workflow execution results + System.out.println(greeting); + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/customannotation/README.md b/core/src/main/java/io/temporal/samples/customannotation/README.md new file mode 100644 index 000000000..f04b25915 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/customannotation/README.md @@ -0,0 +1,9 @@ +# Custom annotation + +The sample demonstrates how to create a custom annotation using an interceptor. In this case the annotation allows specifying an exception of a certain type is benign. + +This samples shows a custom annotation on an activity method, but the same approach can be used for workflow methods or Nexus operations. + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.customannotation.CustomAnnotation +``` From 902591b7d303e6725e5a729513d9eed62a0adedb Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 1 Jul 2025 16:14:28 -0400 Subject: [PATCH 223/240] Sample: Auto Heartbeat via Interceptor (#745) * Sample: Auto Heartbeat via Interceptor Signed-off-by: Tihomir Surdilovic * updates Signed-off-by: Tihomir Surdilovic * updates per recommendations Signed-off-by: Tihomir Surdilovic * formatting fix Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 1 + .../autoheartbeat/AutoHeartbeatUtil.java | 87 +++++++++ .../temporal/samples/autoheartbeat/README.md | 21 +++ .../samples/autoheartbeat/Starter.java | 167 ++++++++++++++++++ .../activities/AutoActivities.java | 29 +++ .../activities/AutoActivitiesImpl.java | 51 ++++++ ...rtbeatActivityInboundCallsInterceptor.java | 108 +++++++++++ .../AutoHeartbeatWorkerInterceptor.java | 30 ++++ .../autoheartbeat/workflows/AutoWorkflow.java | 33 ++++ .../workflows/AutoWorkflowImpl.java | 88 +++++++++ 10 files changed, 615 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/AutoHeartbeatUtil.java create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/README.md create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivities.java create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatActivityInboundCallsInterceptor.java create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatWorkerInterceptor.java create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflowImpl.java diff --git a/README.md b/README.md index f6351bbce..0b8ff8b12 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloDelayedStart**](/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java): Demonstrates how to use delayed start config option when starting a Workflow Executions. - [**HelloSignalWithTimer**](/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java): Demonstrates how to use collect signals for certain amount of time and then process last one. - [**HelloWorkflowTimer**](/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java): Demonstrates how we can use workflow timer to restrict duration of workflow execution instead of workflow run/execution timeouts. + - [**Auto-Heartbeating**](/core/src/main/java/io/temporal/samples/autoheartbeat/): Demonstrates use of Auto-heartbeating utility via activity interceptor. #### Scenario-based samples diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/AutoHeartbeatUtil.java b/core/src/main/java/io/temporal/samples/autoheartbeat/AutoHeartbeatUtil.java new file mode 100644 index 000000000..ca2b0a5f4 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/AutoHeartbeatUtil.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.autoheartbeat; + +import io.temporal.activity.ActivityExecutionContext; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class AutoHeartbeatUtil { + private final long period; + private final long initialDelay; + private final TimeUnit periodTimeUnit; + private final ScheduledExecutorService timerService = + Executors.newSingleThreadScheduledExecutor(); + private final ActivityExecutionContext context; + private final Object details; + private String heartbeaterId; + + public AutoHeartbeatUtil( + long period, + long initialDelay, + TimeUnit periodTimeUnit, + ActivityExecutionContext context, + Object details) { + this.period = period; + this.initialDelay = initialDelay; + this.periodTimeUnit = periodTimeUnit; + this.context = context; + this.details = details; + // Set to activity id better, for sample we just use type + heartbeaterId = context.getInfo().getActivityType(); + } + + public ScheduledFuture start() { + System.out.println("Autoheartbeater[" + heartbeaterId + "] starting..."); + return timerService.scheduleAtFixedRate( + () -> { + // try { + System.out.println( + "Autoheartbeater[" + + heartbeaterId + + "]" + + "heartbeating at: " + + printShortCurrentTime()); + context.heartbeat(details); + }, + initialDelay, + period, + periodTimeUnit); + } + + public void stop() { + System.out.println("Autoheartbeater[" + heartbeaterId + "] being requested to stop."); + // Try not to execute another heartbeat that could have been queued up + // Note this can at times take a second or two so make sure to test this out on your workers + // So can set best heartbeat timeout (sometimes might need larger value to accomodate) + timerService.shutdownNow(); + } + + private String printShortCurrentTime() { + return DateTimeFormatter.ofPattern("HH:mm:ss") + .withZone(ZoneId.systemDefault()) + .format(Instant.now()); + } +} diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/README.md b/core/src/main/java/io/temporal/samples/autoheartbeat/README.md new file mode 100644 index 000000000..946e24fc5 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/README.md @@ -0,0 +1,21 @@ +# Auto-heartbeating sample for activities that define HeartbeatTimeout + +This sample shows an implementation of an "auto-heartbeating" utility that can be applied via interceptor to all +activities where you define HeartbeatTimeout. Use case where this can be helpful include situations where you have +long-running activities where you want to heartbeat but its difficult to explicitly call heartbeat api in activity code +directly. +Another useful scenario for this is where you have activity that at times can complete in very short amount of time, +but then at times can take for example minutes. In this case you have to set longer StartToClose timeout +but you might not want first heartbeat to be sent right away but send it after the "shorter" duration of activity +execution. + +Warning: make sure to test this sample for your use case. This includes load testing. This sample was not +tested on large scale workloads. In addition note that it is recommended to heartbeat from activity code itself. Using +this type of autoheartbeating utility does have disatvantage that activity code itself can continue running after +a handled activity cancelation. Please be aware of these warnings when applying this sample. + +1. Start the Sample: + +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.autoheartbeat.Starter +``` \ No newline at end of file diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java b/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java new file mode 100644 index 000000000..67bb97ec3 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.autoheartbeat; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.CanceledFailure; +import io.temporal.samples.autoheartbeat.activities.AutoActivitiesImpl; +import io.temporal.samples.autoheartbeat.interceptor.AutoHeartbeatWorkerInterceptor; +import io.temporal.samples.autoheartbeat.workflows.AutoWorkflow; +import io.temporal.samples.autoheartbeat.workflows.AutoWorkflowImpl; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerFactoryOptions; + +public class Starter { + static final String TASK_QUEUE = "AutoheartbeatTaskQueue"; + static final String WORKFLOW_ID = "AutoHeartbeatWorkflow"; + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + // Configure our auto heartbeat workflow interceptor which will apply + // AutoHeartbeaterUtil to each activity workflow schedules which has a heartbeat + // timeout configured + WorkerFactoryOptions wfo = + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors(new AutoHeartbeatWorkerInterceptor()) + .build(); + + WorkerFactory factory = WorkerFactory.newInstance(client, wfo); + Worker worker = factory.newWorker(TASK_QUEUE); + + worker.registerWorkflowImplementationTypes(AutoWorkflowImpl.class); + worker.registerActivitiesImplementations(new AutoActivitiesImpl()); + + factory.start(); + + // first run completes execution with autoheartbeat utils + firstRun(client); + // second run cancels running (pending) activity via signal (specific scope cancel) + secondRun(client); + // third run cancels running execution which cancels activity as well + thirdRun(client); + // fourth run turns off autoheartbeat for activities and lets activity time out on heartbeat + // timeout + fourthRun(client); + + System.exit(0); + } + + @SuppressWarnings("unused") + private static void firstRun(WorkflowClient client) { + System.out.println("**** First Run: run workflow to completion"); + AutoWorkflow firstRun = + client.newWorkflowStub( + AutoWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + try { + String firstRunResult = firstRun.exec("Auto heartbeating is cool"); + System.out.println("First run result: " + firstRunResult); + } catch (Exception e) { + System.out.println("First run - Workflow exec exception: " + e.getClass().getName()); + } + } + + @SuppressWarnings("unused") + private static void secondRun(WorkflowClient client) { + System.out.println("\n\n**** Second Run: cancel activities via signal"); + AutoWorkflow secondRun = + client.newWorkflowStub( + AutoWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + WorkflowClient.start(secondRun::exec, "Auto heartbeating is cool"); + doSleeps(4); + secondRun.cancelActivity(); + + try { + String secondRunResult = WorkflowStub.fromTyped(secondRun).getResult(String.class); + System.out.println("Second run result: " + secondRunResult); + } catch (Exception e) { + System.out.println("Second run - Workflow exec exception: " + e.getClass().getName()); + } + } + + @SuppressWarnings("unused") + private static void thirdRun(WorkflowClient client) { + System.out.println("\n\n**** Third Run: cancel workflow execution"); + AutoWorkflow thirdRun = + client.newWorkflowStub( + AutoWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + WorkflowClient.start(thirdRun::exec, "Auto heartbeating is cool"); + doSleeps(10); + try { + WorkflowStub.fromTyped(thirdRun).cancel(); + String thirdRunResult = WorkflowStub.fromTyped(thirdRun).getResult(String.class); + System.out.println("Third run result: " + thirdRunResult); + } catch (Exception e) { + // we are expecting workflow cancelation + if (e.getCause() instanceof CanceledFailure) { + System.out.println("Third run - Workflow execution canceled."); + } else { + System.out.println("Third run - Workflow exec exception: " + e.getMessage()); + } + } + } + + @SuppressWarnings("unused") + private static void fourthRun(WorkflowClient client) { + System.out.println("\n\n**** Fourth Run: cause heartbeat timeout"); + // we disable autoheartbeat via env var + System.setProperty("sample.disableAutoHeartbeat", "true"); + AutoWorkflow fourth = + client.newWorkflowStub( + AutoWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId(WORKFLOW_ID) + .setTaskQueue(TASK_QUEUE) + .build()); + + try { + String fourthRunResult = fourth.exec("Auto heartbeating is cool"); + System.out.println("Fourth run result: " + fourthRunResult); + } catch (Exception e) { + System.out.println("Fourth run - Workflow exec exception: " + e.getClass().getName()); + } + } + + private static void doSleeps(int seconds) { + try { + Thread.sleep(seconds * 1000L); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } +} diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivities.java b/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivities.java new file mode 100644 index 000000000..81726e05a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivities.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.autoheartbeat.activities; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface AutoActivities { + String runActivityOne(String input); + + String runActivityTwo(String input); +} diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivitiesImpl.java b/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivitiesImpl.java new file mode 100644 index 000000000..26a30162d --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivitiesImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.autoheartbeat.activities; + +import java.util.concurrent.TimeUnit; + +public class AutoActivitiesImpl implements AutoActivities { + + @Override + public String runActivityOne(String input) { + return runActivity("runActivityOne - " + input, 10); + } + + @Override + public String runActivityTwo(String input) { + return runActivity("runActivityTwo - " + input, 5); + } + + @SuppressWarnings("FutureReturnValueIgnored") + private String runActivity(String input, int seconds) { + for (int i = 0; i < seconds; i++) { + sleep(1); + } + return "Activity completed: " + input; + } + + private void sleep(int seconds) { + try { + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); + } catch (InterruptedException ee) { + // Empty + } + } +} diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatActivityInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatActivityInboundCallsInterceptor.java new file mode 100644 index 000000000..60a2d5427 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatActivityInboundCallsInterceptor.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.autoheartbeat.interceptor; + +import io.temporal.activity.Activity; +import io.temporal.activity.ActivityExecutionContext; +import io.temporal.client.ActivityCanceledException; +import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; +import io.temporal.common.interceptors.ActivityInboundCallsInterceptorBase; +import io.temporal.samples.autoheartbeat.AutoHeartbeatUtil; +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class AutoHeartbeatActivityInboundCallsInterceptor + extends ActivityInboundCallsInterceptorBase { + private ActivityExecutionContext activityExecutionContext; + private Duration activityHeartbeatTimeout; + private AutoHeartbeatUtil autoHeartbeater; + private ScheduledFuture scheduledFuture; + + public AutoHeartbeatActivityInboundCallsInterceptor(ActivityInboundCallsInterceptor next) { + super(next); + } + + @Override + public void init(ActivityExecutionContext context) { + this.activityExecutionContext = context; + activityHeartbeatTimeout = activityExecutionContext.getInfo().getHeartbeatTimeout(); + super.init(context); + } + + @Override + @SuppressWarnings({"FutureReturnValueIgnored", "CatchAndPrintStackTrace"}) + public ActivityOutput execute(ActivityInput input) { + // If activity has heartbeat timeout defined we want to apply auto-heartbeter + // Unless we explicitly disabled autoheartbeating via system property + if (activityHeartbeatTimeout != null + && activityHeartbeatTimeout.getSeconds() > 0 + && !Boolean.parseBoolean(System.getProperty("sample.disableAutoHeartbeat"))) { + System.out.println( + "Auto heartbeating applied for activity: " + + activityExecutionContext.getInfo().getActivityType()); + autoHeartbeater = + new AutoHeartbeatUtil(2, 0, TimeUnit.SECONDS, activityExecutionContext, input); + scheduledFuture = autoHeartbeater.start(); + } else { + System.out.println( + "Auto heartbeating not being applied for activity: " + + activityExecutionContext.getInfo().getActivityType()); + } + + if (scheduledFuture != null) { + CompletableFuture activityExecFuture = + CompletableFuture.supplyAsync(() -> super.execute(input)); + CompletableFuture autoHeartbeatFuture = + CompletableFuture.supplyAsync( + () -> { + try { + return scheduledFuture.get(); + } catch (Exception e) { + throw new ActivityCanceledException(activityExecutionContext.getInfo()); + } + }); + try { + return (ActivityOutput) + CompletableFuture.anyOf(autoHeartbeatFuture, activityExecFuture).get(); + } catch (Exception e) { + if (e instanceof ExecutionException) { + ExecutionException ee = (ExecutionException) e; + if (ee.getCause() instanceof ActivityCanceledException) { + throw new ActivityCanceledException(activityExecutionContext.getInfo()); + } + } + throw Activity.wrap(e); + } finally { + if (autoHeartbeater != null) { + autoHeartbeater.stop(); + } + } + } else { + return super.execute(input); + } + } + + public interface AutoHeartbeaterCancellationCallback { + void handle(Exception e); + } +} diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatWorkerInterceptor.java new file mode 100644 index 000000000..9816fe644 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatWorkerInterceptor.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.autoheartbeat.interceptor; + +import io.temporal.common.interceptors.ActivityInboundCallsInterceptor; +import io.temporal.common.interceptors.WorkerInterceptorBase; + +public class AutoHeartbeatWorkerInterceptor extends WorkerInterceptorBase { + @Override + public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) { + return new AutoHeartbeatActivityInboundCallsInterceptor(next); + } +} diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflow.java b/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflow.java new file mode 100644 index 000000000..e8816c6a2 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflow.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.autoheartbeat.workflows; + +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface AutoWorkflow { + @WorkflowMethod + String exec(String input); + + @SignalMethod + void cancelActivity(); +} diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflowImpl.java b/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflowImpl.java new file mode 100644 index 000000000..6ff8100eb --- /dev/null +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflowImpl.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package io.temporal.samples.autoheartbeat.workflows; + +import io.temporal.activity.ActivityCancellationType; +import io.temporal.activity.ActivityOptions; +import io.temporal.common.RetryOptions; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.CanceledFailure; +import io.temporal.failure.TimeoutFailure; +import io.temporal.samples.autoheartbeat.activities.AutoActivities; +import io.temporal.workflow.CancellationScope; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class AutoWorkflowImpl implements AutoWorkflow { + private CancellationScope scope; + + @Override + public String exec(String input) { + AutoActivities activitiesOne = + Workflow.newActivityStub( + AutoActivities.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(22)) + .setHeartbeatTimeout(Duration.ofSeconds(8)) + .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED) + // for sample purposes + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(3).build()) + .build()); + + AutoActivities activitiesTwo = + Workflow.newActivityStub( + AutoActivities.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(20)) + .setHeartbeatTimeout(Duration.ofSeconds(7)) + .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED) + // for sample purposes + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(3).build()) + .build()); + + // Start our activity in CancellationScope so we can cancel it if needed + scope = + Workflow.newCancellationScope( + () -> { + activitiesOne.runActivityOne(input); + activitiesTwo.runActivityTwo(input); + }); + + try { + scope.run(); + } catch (ActivityFailure e) { + if (e.getCause() instanceof CanceledFailure) { + // We dont want workflow to fail in we canceled our scope, just log and return + return "Workflow result after activity cancellation"; + } else if (e.getCause() instanceof TimeoutFailure) { + return "Workflow result after activity timeout of type: " + + ((TimeoutFailure) e.getCause()).getTimeoutType().name(); + } else { + throw e; + } + } + return "completed"; + } + + @Override + public void cancelActivity() { + scope.cancel("Canceling scope from signal handler"); + } +} From 84b4fee783949b4dce798b6142e2f700342f9d00 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Sun, 20 Jul 2025 11:42:01 -0400 Subject: [PATCH 224/240] Async package delivery sample (#746) * [WIP] Async package delivery sample Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * adding cancelation and failure Signed-off-by: Tihomir Surdilovic * adding readme Signed-off-by: Tihomir Surdilovic * update readme Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic * update starter Signed-off-by: Tihomir Surdilovic * update readme Signed-off-by: Tihomir Surdilovic * update readme Signed-off-by: Tihomir Surdilovic * add comment Signed-off-by: Tihomir Surdilovic * update readme Signed-off-by: Tihomir Surdilovic * remove duplicate comment Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- README.md | 3 + .../samples/packetdelivery/Packet.java | 21 +++ .../packetdelivery/PacketDelivery.java | 124 ++++++++++++++ .../PacketDeliveryActivities.java | 15 ++ .../PacketDeliveryActivitiesImpl.java | 161 ++++++++++++++++++ .../PacketDeliveryWorkflow.java | 22 +++ .../PacketDeliveryWorkflowImpl.java | 79 +++++++++ .../samples/packetdelivery/PacketUtils.java | 8 + .../temporal/samples/packetdelivery/README.md | 24 +++ .../samples/packetdelivery/Starter.java | 70 ++++++++ 10 files changed, 527 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/Packet.java create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/PacketDelivery.java create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivities.java create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflowImpl.java create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/PacketUtils.java create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/README.md create mode 100644 core/src/main/java/io/temporal/samples/packetdelivery/Starter.java diff --git a/README.md b/README.md index 0b8ff8b12..1cbf700c9 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,9 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Custom Annotation**](/core/src/main/java/io/temporal/samples/customannotation): Demonstrates how to create a custom annotation using an interceptor. +- [**Asnyc Packet Delivery**](/core/src/main/java/io/temporal/samples/packetdelivery): Demonstrates running multiple execution paths async within single execution. + + #### API demonstrations - [**Async Untyped Child Workflow**](/core/src/main/java/io/temporal/samples/asyncuntypedchild): Demonstrates how to invoke an untyped child workflow async, that can complete after parent workflow is already completed. diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/Packet.java b/core/src/main/java/io/temporal/samples/packetdelivery/Packet.java new file mode 100644 index 000000000..2d7ee91d4 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/Packet.java @@ -0,0 +1,21 @@ +package io.temporal.samples.packetdelivery; + +public class Packet { + private int id; + private String content; + + public Packet() {} + + public Packet(int id, String content) { + this.id = id; + this.content = content; + } + + public int getId() { + return id; + } + + public String getContent() { + return content; + } +} diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDelivery.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDelivery.java new file mode 100644 index 000000000..334d21bcb --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDelivery.java @@ -0,0 +1,124 @@ +package io.temporal.samples.packetdelivery; + +import io.temporal.activity.ActivityOptions; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.*; +import java.time.Duration; +import org.slf4j.Logger; + +public class PacketDelivery { + private Packet packet; + private boolean deliveryConfirmation = false; + private boolean needDeliveryConfirmation = false; + private CompletablePromise delivered = Workflow.newPromise(); + private CancellationScope cancellationScope; + + private Logger logger = Workflow.getLogger(this.getClass().getName()); + + private final PacketDeliveryActivities activities = + Workflow.newActivityStub( + PacketDeliveryActivities.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(5)) + .setHeartbeatTimeout(Duration.ofSeconds(2)) + .build()); + + private final PacketDeliveryActivities compensationActivities = + Workflow.newActivityStub( + PacketDeliveryActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(3)).build()); + + public PacketDelivery(Packet packet) { + this.packet = packet; + processDeliveryAsync(); + } + + public Promise getDelivered() { + return delivered; + } + + public void processDeliveryAsync() { + delivered.completeFrom(Async.procedure(this::processDelivery)); + } + + public void processDelivery() { + cancellationScope = + Workflow.newCancellationScope( + () -> { + String deliveryConfirmationResult = ""; + while (!deliveryConfirmationResult.equals(PacketUtils.COMPLETION_SUCCESS)) { + // Step 1 perform delivery + logger.info( + "** Performing delivery for packet: " + + packet.getId() + + " - " + + packet.getContent()); + activities.performDelivery(packet); + // Step 2 wait for delivery confirmation + logger.info( + "** Delivery for packet: " + + packet.getId() + + " - " + + packet.getContent() + + " awaiting delivery confirmation"); + needDeliveryConfirmation = true; + Workflow.await(() -> deliveryConfirmation); + logger.info( + "** Delivery for packet: " + + packet.getId() + + " - " + + packet.getContent() + + " received confirmation"); + // Step 3 complete delivery processing + logger.info( + "** Completing delivery for packet: " + + packet.getId() + + " - " + + packet.getContent()); + deliveryConfirmationResult = activities.completeDelivery(packet); + // Reset deliveryConfirmation and needDeliveryConfirmation + deliveryConfirmation = false; + needDeliveryConfirmation = false; + } + }); + + try { + cancellationScope.run(); + } catch (Exception e) { + if (e instanceof ActivityFailure) { + ActivityFailure activityFailure = (ActivityFailure) e; + if (activityFailure.getCause() instanceof CanceledFailure) { + // Run compensation activity and complete + compensationActivities.compensateDelivery(packet); + } + } + // Just for show for example that cancel could come in while we are waiting on approval signal + // too + else if (e instanceof CanceledFailure) { + needDeliveryConfirmation = false; + // Run compensation activity and complete + compensationActivities.compensateDelivery(packet); + } + return; + } + } + + public void confirmDelivery() { + this.deliveryConfirmation = true; + } + + public void cancelDelivery(String reason) { + if (cancellationScope != null) { + cancellationScope.cancel(reason); + } + } + + public boolean isNeedDeliveryConfirmation() { + return needDeliveryConfirmation; + } + + public Packet getPacket() { + return packet; + } +} diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivities.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivities.java new file mode 100644 index 000000000..b2e67dbab --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivities.java @@ -0,0 +1,15 @@ +package io.temporal.samples.packetdelivery; + +import io.temporal.activity.ActivityInterface; +import java.util.List; + +@ActivityInterface +public interface PacketDeliveryActivities { + List generatePackets(); + + void performDelivery(Packet packet); + + String completeDelivery(Packet packet); + + String compensateDelivery(Packet packet); +} diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivitiesImpl.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivitiesImpl.java new file mode 100644 index 000000000..655223501 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivitiesImpl.java @@ -0,0 +1,161 @@ +package io.temporal.samples.packetdelivery; + +import io.temporal.activity.Activity; +import io.temporal.activity.ActivityExecutionContext; +import io.temporal.client.ActivityCompletionException; +import io.temporal.client.WorkflowClient; +import java.util.*; + +public class PacketDeliveryActivitiesImpl implements PacketDeliveryActivities { + private List packets = + Arrays.asList( + new Packet(1, "books"), + new Packet(2, "jewelry"), + new Packet(3, "furniture"), + new Packet(4, "food"), + new Packet(5, "electronics")); + private WorkflowClient client; + + public PacketDeliveryActivitiesImpl(WorkflowClient client) { + this.client = client; + } + + @Override + public List generatePackets() { + return packets; + } + + @Override + public void performDelivery(Packet packet) { + ActivityExecutionContext context = Activity.getExecutionContext(); + System.out.println( + "** Activity - Performing delivery for packet: " + + packet.getId() + + " with content: " + + packet.getContent()); + for (int i = 0; i < 4; i++) { + try { + // Perform the heartbeat. Used to notify the workflow that activity execution is alive + context.heartbeat(i); + } catch (ActivityCompletionException e) { + System.out.println( + "** Activity - Canceling delivery activity for packet: " + + packet.getId() + + " with content: " + + packet.getContent()); + throw e; + } + } + } + + @Override + public String completeDelivery(Packet packet) { + ActivityExecutionContext context = Activity.getExecutionContext(); + System.out.println( + "** Activity - Completing delivery for package: " + + packet.getId() + + " with content: " + + packet.getContent()); + for (int i = 0; i < 4; i++) { + try { + // Perform the heartbeat. Used to notify the workflow that activity execution is alive + context.heartbeat(i); + } catch (ActivityCompletionException e) { + System.out.println( + "** Activity - Canceling complete delivery activity for packet: " + + packet.getId() + + " with content: " + + packet.getContent()); + throw e; + } + } + // For sample we just confirm + return randomCompletionDeliveryResult(packet); + } + + @Override + public String compensateDelivery(Packet packet) { + System.out.println( + "** Activity - Compensating delivery for package: " + + packet.getId() + + " with content: " + + packet.getContent()); + sleep(1); + return PacketUtils.COMPENSATION_COMPLETED; + } + + /** + * For this sample activity completion result can drive if 1. Delivery confirmation is completed, + * in which case we complete delivery 2. Delivery confirmation is failed, in which case we run the + * delivery again 3. Delivery confirmation is cancelled, in which case we want to cancel delivery + * and perform "cleanup activity" Note that any delivery can cancel itself OR another delivery, so + * for example Furniure delivery can cancel the Food delivery. For sample we have some specific + * rules Which delivery can cancel which + */ + private String randomCompletionDeliveryResult(Packet packet) { + Random random = new Random(); + double randomValue = random.nextDouble(); + if (randomValue < 0.10) { // 10% chance for delivery completion to be canceled + int toCancelDelivery = determineCancelRules(packet); + System.out.println( + "** Activity - Delivery completion result for package: " + + packet.getId() + + " with content: " + + packet.getContent() + + ": " + + "Cancelling delivery: " + + toCancelDelivery); + + // send cancellation signal for packet to be canceled + PacketDeliveryWorkflow packetWorkflow = + client.newWorkflowStub( + PacketDeliveryWorkflow.class, + Activity.getExecutionContext().getInfo().getWorkflowId()); + packetWorkflow.cancelDelivery(toCancelDelivery, "canceled from delivery " + packet.getId()); + + return PacketUtils.COMPLETION_CANCELLED; + } + if (randomValue < 0.20) { // 20% chance for delivery completion to fail + System.out.println( + "** Activity - Delivery completion result for package: " + + packet.getId() + + " with content: " + + packet.getContent() + + ": " + + "Failed"); + return PacketUtils.COMPLETION_FAILURE; + } + + System.out.println( + "** Activity - Delivery completion result for package: " + + packet.getId() + + " with content: " + + packet.getContent() + + ": " + + "Successful"); + return PacketUtils.COMPLETION_SUCCESS; + } + + private void sleep(int seconds) { + try { + Thread.sleep(seconds * 1000L); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + + /** + * Sample rules for canceling different deliveries We just rotate the list 1-5 (packet ids) by + * packet id and return first result + */ + private int determineCancelRules(Packet packet) { + List list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); + Collections.rotate(list, packet.getId()); + System.out.println( + "** Activity - Package delivery : " + + packet.getId() + + " canceling package delivery: " + + list.get(0)); + return list.get(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflow.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflow.java new file mode 100644 index 000000000..1f48fac08 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflow.java @@ -0,0 +1,22 @@ +package io.temporal.samples.packetdelivery; + +import io.temporal.workflow.QueryMethod; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.util.List; + +@WorkflowInterface +public interface PacketDeliveryWorkflow { + @WorkflowMethod + String execute(); + + @SignalMethod + void confirmDelivery(int deliveryId); + + @SignalMethod + void cancelDelivery(int deliveryId, String reason); + + @QueryMethod + List deliveryConfirmationPackets(); +} diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflowImpl.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflowImpl.java new file mode 100644 index 000000000..6236458d3 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflowImpl.java @@ -0,0 +1,79 @@ +package io.temporal.samples.packetdelivery; + +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.slf4j.Logger; + +public class PacketDeliveryWorkflowImpl implements PacketDeliveryWorkflow { + private final Map packetDeliveries = new HashMap<>(); + private final Logger logger = Workflow.getLogger(this.getClass().getName()); + + private final PacketDeliveryActivities activities = + Workflow.newActivityStub( + PacketDeliveryActivities.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(5)) + .setHeartbeatTimeout(Duration.ofSeconds(2)) + .build()); + + @Override + public String execute() { + List> packetsDelivered = new ArrayList<>(); + // Step 1 - upload initial packets to deliver + List initialPackets = activities.generatePackets(); + // Step 2 - set up delivery processing + for (Packet packet : initialPackets) { + PacketDelivery delivery = new PacketDelivery(packet); + packetDeliveries.put(packet.getId(), delivery); + packetsDelivered.add(delivery.getDelivered()); + } + + // Wait for all packet deliveries to complete + Promise.allOf(packetsDelivered).get(); + return "completed"; + } + + @Override + public void confirmDelivery(int deliveryId) { + if (packetDeliveries.containsKey(deliveryId)) { + packetDeliveries.get(deliveryId).confirmDelivery(); + } + } + + @Override + public void cancelDelivery(int deliveryId, String reason) { + if (packetDeliveries.containsKey(deliveryId)) { + // Only makes sense to cancel if delivery is not done yet + if (!packetDeliveries.get(deliveryId).getDelivered().isCompleted()) { + logger.info("Sending cancellation for delivery : " + deliveryId + " and reason: " + reason); + packetDeliveries.get(deliveryId).cancelDelivery(reason); + } + logger.info( + "Bypassing sending cancellation for delivery : " + + deliveryId + + " and reason: " + + reason + + " because delivery already completed"); + } + } + + @Override + public List deliveryConfirmationPackets() { + List confirmationPackets = new ArrayList<>(); + packetDeliveries + .values() + .forEach( + p -> { + if (p.isNeedDeliveryConfirmation()) { + confirmationPackets.add(p.getPacket()); + } + }); + return confirmationPackets; + } +} diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketUtils.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketUtils.java new file mode 100644 index 000000000..193a2f4be --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketUtils.java @@ -0,0 +1,8 @@ +package io.temporal.samples.packetdelivery; + +public class PacketUtils { + public static String COMPLETION_SUCCESS = "Delivery Completion Successful"; + public static String COMPLETION_FAILURE = "Delivery Completion Failed"; + public static String COMPLETION_CANCELLED = "Delivery Completion Cancelled"; + public static String COMPENSATION_COMPLETED = "Delivery Compensation Completed"; +} diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/README.md b/core/src/main/java/io/temporal/samples/packetdelivery/README.md new file mode 100644 index 000000000..d43309990 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/README.md @@ -0,0 +1,24 @@ +# Async Package Delivery Sample + +This sample show how to run multiple "paths" of execution async within single workflow. +Sample starts deliveries of 5 items in parallel. Each item performs an activity +and then waits for a confirmation signal, then performs second activity. + +Workflow waits until all packets have been delivered. Each packet delivery path can choose to +also "cancel" delivery of another item. This is done via signal and cancellation of the +CancellationScope. + +## Notes +1. In this sample we do not handle event history count and size partitioning via ContinueAsNew. It is assumed +that the total number of paths and path lengths (in terms of activity executions) would not exceed it. +For your use case you might need to add ContinueAsNew checks to deal with this situation. +2. Use this sample as all other ones as reference for your implementation. It was not tested on high scale +so using it as-is without load testing is not recommended. + +## Start the Sample: +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.packetdelivery.Starter +``` + +Run sample multiple times to see different scenarios (delivery failure and retry and delivery cancelation) +There is a 10% chance delivery is going to be canceled and 20% chane it will fail. \ No newline at end of file diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java b/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java new file mode 100644 index 000000000..e1d97e621 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java @@ -0,0 +1,70 @@ +package io.temporal.samples.packetdelivery; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowNotFoundException; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import java.util.Collections; +import java.util.List; + +public class Starter { + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker("packet-delivery-taskqueue"); + + worker.registerWorkflowImplementationTypes(PacketDeliveryWorkflowImpl.class); + worker.registerActivitiesImplementations(new PacketDeliveryActivitiesImpl(client)); + + factory.start(); + + PacketDeliveryWorkflow workflow = + client.newWorkflowStub( + PacketDeliveryWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId("packet-delivery-workflow") + .setTaskQueue("packet-delivery-taskqueue") + .build()); + + WorkflowClient.start(workflow::execute); + + // start completing package deliveries (send confirmations) + // Query workflow for packets that need confirmation, confirm until none need confirmation any + // more + while (true) { + sleep(3); + List packets = workflow.deliveryConfirmationPackets(); + if (packets.isEmpty()) { + break; + } + // for "fun", reverse the list we get from delivery confirmation list + Collections.reverse(packets); + + for (Packet p : packets) { + try { + workflow.confirmDelivery(p.getId()); + } catch (WorkflowNotFoundException e) { + // In some cases with cancellations happening, workflow could be completed by now + // We just ignore and exit out of loop + break; + } + } + } + + // wait for workflow to complete + String result = WorkflowStub.fromTyped(workflow).getResult(String.class); + System.out.println("** Workflow Result: " + result); + } + + private static void sleep(int seconds) { + try { + Thread.sleep(seconds * 1000L); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } +} From 11bbbbe75a51fb3057842ad9e0cbb7a99b98cce1 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Sun, 20 Jul 2025 11:42:14 -0400 Subject: [PATCH 225/240] add replayer test with worker interceptor (#747) * add replayer test with worker interceptor Signed-off-by: Tihomir Surdilovic * update Signed-off-by: Tihomir Surdilovic --------- Signed-off-by: Tihomir Surdilovic --- .../InterceptorReplayTest.java | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 core/src/test/java/io/temporal/samples/interceptorreplaytest/InterceptorReplayTest.java diff --git a/core/src/test/java/io/temporal/samples/interceptorreplaytest/InterceptorReplayTest.java b/core/src/test/java/io/temporal/samples/interceptorreplaytest/InterceptorReplayTest.java new file mode 100644 index 000000000..97ea42ec8 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/interceptorreplaytest/InterceptorReplayTest.java @@ -0,0 +1,191 @@ +package io.temporal.samples.interceptorreplaytest; + +import static org.junit.Assert.fail; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityOptions; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.WorkflowExecutionHistory; +import io.temporal.common.interceptors.*; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.testing.WorkflowReplayer; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.time.Duration; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class InterceptorReplayTest { + @RegisterExtension + public static final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + // Register workflow and activity impls + .registerWorkflowImplementationTypes(TestWorkflowImpl.class) + .setActivityImplementations(new TestActivitiesImpl()) + // Register worker interceptor + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors(new TestWorkerInterceptor()) + .build()) + .setDoNotStart(true) + .build(); + + @Test + public void testReplayWithInterceptors(TestWorkflowEnvironment testEnv, Worker worker) { + // Run our test workflow. We need to set workflow id so can get history after + testEnv.start(); + TestWorkflow workflow = + testEnv + .getWorkflowClient() + .newWorkflowStub( + TestWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId("test-workflow") + .setTaskQueue(worker.getTaskQueue()) + .build()); + workflow.execute(); + + // Replay execution with history of just executed + WorkflowExecutionHistory eventHistory = + testEnv.getWorkflowClient().fetchHistory("test-workflow"); + + try { + WorkflowReplayer.replayWorkflowExecution(eventHistory, worker); + } catch (Exception e) { + fail(e.getMessage()); + } + testEnv.shutdown(); + + // Try replaying execution with test env where we dont have interceptors registered + TestWorkflowEnvironment testEnv2 = TestWorkflowEnvironment.newInstance(); + Worker testEnv2Worker = testEnv2.newWorker("test-taskqueue"); + testEnv2Worker.registerWorkflowImplementationTypes(TestWorkflowImpl.class); + testEnv2Worker.registerActivitiesImplementations(new TestActivitiesImpl()); + + testEnv2.start(); + + // Replay should fail with worker that does not have interceptor registered + try { + WorkflowReplayer.replayWorkflowExecution(eventHistory, testEnv2Worker); + fail("This should have failed"); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + + // But it should be fine with worker that does + try { + WorkflowReplayer.replayWorkflowExecution(eventHistory, worker); + } catch (Exception e) { + fail(e.getMessage()); + } + + testEnv2.shutdown(); + } + + // Test workflow and activities + @WorkflowInterface + public interface TestWorkflow { + @WorkflowMethod + void execute(); + } + + public static class TestWorkflowImpl implements TestWorkflow { + + TestActivities activities = + Workflow.newActivityStub( + TestActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public void execute() { + activities.activityOne(); + } + } + + @ActivityInterface + public interface TestActivities { + void activityOne(); + + void activityTwo(); + + void activityThree(); + } + + public static class TestActivitiesImpl implements TestActivities { + @Override + public void activityOne() { + System.out.println("Activities one done"); + } + + @Override + public void activityTwo() { + System.out.println("Activities two done"); + } + + @Override + public void activityThree() { + System.out.println("Activities three done"); + } + } + + // Test worker and workflow interceptors + public static class TestWorkerInterceptor extends WorkerInterceptorBase { + @Override + public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) { + return new TestWorkflowInboundCallsInterceptor(next); + } + } + + public static class TestWorkflowInboundCallsInterceptor + extends WorkflowInboundCallsInterceptorBase { + TestActivities activities = + Workflow.newActivityStub( + TestActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + public TestWorkflowInboundCallsInterceptor(WorkflowInboundCallsInterceptor next) { + super(next); + } + + @Override + public void init(WorkflowOutboundCallsInterceptor outboundCalls) { + super.init(new TestWorkflowOutboundCallsInterceptor(outboundCalls)); + } + + @Override + public WorkflowOutput execute(WorkflowInput input) { + WorkflowOutput output = super.execute(input); + // Run activity three before completing execution + activities.activityThree(); + return output; + } + } + + public static class TestWorkflowOutboundCallsInterceptor + extends WorkflowOutboundCallsInterceptorBase { + TestActivities activities = + Workflow.newActivityStub( + TestActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + public TestWorkflowOutboundCallsInterceptor(WorkflowOutboundCallsInterceptor next) { + super(next); + } + + @Override + public ActivityOutput executeActivity(ActivityInput input) { + ActivityOutput output = super.executeActivity(input); + + // we only want to intercept ActivityOne here + if (input.getActivityName().equals("ActivityOne")) { + activities.activityTwo(); + } + + return output; + } + } +} From c126e311dd13db336acb615202846ad658020926 Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Mon, 28 Jul 2025 18:44:25 -0400 Subject: [PATCH 226/240] HelloSignalWithStartAndWorkflowInit sample (#748) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * HelloSignalWithStartAndWorkflowInit sample Signed-off-by: Tihomir Surdilovic * update readme Signed-off-by: Tihomir Surdilovic * update workflowid Signed-off-by: Tihomir Surdilovic * adding test Signed-off-by: Tihomir Surdilovic * Update core/src/test/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInitTest.java Co-authored-by: Antonio Mendoza PΓ©rez --------- Signed-off-by: Tihomir Surdilovic Co-authored-by: Antonio Mendoza PΓ©rez --- README.md | 2 +- .../HelloSignalWithStartAndWorkflowInit.java | 208 ++++++++++++++++++ .../java/io/temporal/samples/hello/README.md | 1 + ...lloSignalWithStartAndWorkflowInitTest.java | 76 +++++++ 4 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInitTest.java diff --git a/README.md b/README.md index 1cbf700c9..a62ed4c98 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**HelloSignalWithTimer**](/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java): Demonstrates how to use collect signals for certain amount of time and then process last one. - [**HelloWorkflowTimer**](/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java): Demonstrates how we can use workflow timer to restrict duration of workflow execution instead of workflow run/execution timeouts. - [**Auto-Heartbeating**](/core/src/main/java/io/temporal/samples/autoheartbeat/): Demonstrates use of Auto-heartbeating utility via activity interceptor. - + - [**HelloSignalWithStartAndWorkflowInit**](/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java): Demonstrates how WorkflowInit can be useful with SignalWithStart to initialize workflow variables. #### Scenario-based samples diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java new file mode 100644 index 000000000..096516b10 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java @@ -0,0 +1,208 @@ +package io.temporal.samples.hello; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityOptions; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.*; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang.StringUtils; + +/** + * Sample Temporal workflow that demonstrates how to use WorkflowInit with clients starting + * execution using SignalWithStart + */ +public class HelloSignalWithStartAndWorkflowInit { + static final String TASK_QUEUE = "HelloWithInitTaskQueue"; + + public interface MyWorkflow { + @WorkflowMethod + String greet(Person person); + + @SignalMethod + void addGreeting(Person person); + } + + @WorkflowInterface + public interface MyWorkflowWithInit extends MyWorkflow {} + + @WorkflowInterface + public interface MyWorkflowNoInit extends MyWorkflow {} + + public static class WithInitMyWorkflowImpl implements MyWorkflowWithInit { + // We dont initialize peopleToGreet on purpose + private List peopleToGreet; + private MyGreetingActivities activities = + Workflow.newActivityStub( + MyGreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @WorkflowInit + public WithInitMyWorkflowImpl(Person person) { + peopleToGreet = new ArrayList<>(); + } + + @Override + public String greet(Person person) { + peopleToGreet.add(person); + List greetings = new ArrayList<>(); + + while (!peopleToGreet.isEmpty()) { + // run activity... + greetings.add(activities.greet(peopleToGreet.get(0))); + peopleToGreet.remove(0); + } + return StringUtils.join(greetings, ","); + } + + @Override + public void addGreeting(Person person) { + peopleToGreet.add(person); + } + } + + public static class WithoutInitMyWorkflowImpl implements MyWorkflowNoInit { + // We dont initialize peopleToGreet on purpose + private List peopleToGreet; + private MyGreetingActivities activities = + Workflow.newActivityStub( + MyGreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build()); + + @Override + public String greet(Person person) { + peopleToGreet.add(person); + List greetings = new ArrayList<>(); + + while (!peopleToGreet.isEmpty()) { + // run activity... + greetings.add(activities.greet(peopleToGreet.get(0))); + peopleToGreet.remove(0); + } + return StringUtils.join(greetings, ","); + } + + @Override + public void addGreeting(Person person) { + peopleToGreet.add(person); + } + } + + @ActivityInterface + public interface MyGreetingActivities { + public String greet(Person person); + } + + public static class MyGreetingActivitiesImpl implements MyGreetingActivities { + @Override + public String greet(Person person) { + return "Hello " + person.firstName + " " + person.lastName; + } + } + + public static class Person { + String firstName; + String lastName; + int age; + + public Person() {} + + public Person(String firstName, String lastName, int age) { + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(TASK_QUEUE); + + worker.registerWorkflowImplementationTypes(WithInitMyWorkflowImpl.class); + // We explicitly want to fail this workflow on NPE as thats what we expect without WorkflowInit + // As we didnt initialize peopleToGreet on purpose + worker.registerWorkflowImplementationTypes( + WorkflowImplementationOptions.newBuilder() + .setFailWorkflowExceptionTypes(NullPointerException.class) + .build(), + WithoutInitMyWorkflowImpl.class); + worker.registerActivitiesImplementations(new MyGreetingActivitiesImpl()); + + factory.start(); + + MyWorkflowWithInit withInitStub = + client.newWorkflowStub( + MyWorkflowWithInit.class, + WorkflowOptions.newBuilder() + .setWorkflowId("with-init") + .setTaskQueue(TASK_QUEUE) + .build()); + // Start with init workflow which is expected to succeed + // As WorkflowInit will initialize peopleToGreet before signal handler is invoked + WorkflowStub.fromTyped(withInitStub) + .signalWithStart( + "addGreeting", + new Object[] {new Person("Michael", "Jordan", 55)}, + new Object[] {new Person("John", "Stockton", 57)}); + + String result = WorkflowStub.fromTyped(withInitStub).getResult(String.class); + System.out.println("Result: " + result); + + // Start without init, this execution is expected to fail as we set + // NullPointerException as a workflow failure type + // NPE is caused because we did not initialize peopleToGreet array + MyWorkflowNoInit noInitStub = + client.newWorkflowStub( + MyWorkflowNoInit.class, + WorkflowOptions.newBuilder() + .setWorkflowId("without-init") + .setTaskQueue(TASK_QUEUE) + .build()); + WorkflowStub.fromTyped(noInitStub) + .signalWithStart( + "addGreeting", + new Object[] {new Person("Michael", "Jordan", 55)}, + new Object[] {new Person("John", "Stockton", 57)}); + try { + WorkflowStub.fromTyped(noInitStub).getResult(String.class); + } catch (WorkflowFailedException e) { + System.out.println("Expected workflow failure: " + e.getMessage()); + } + + System.exit(0); + } +} diff --git a/core/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md index 41dd18271..c8ebbdb42 100644 --- a/core/src/main/java/io/temporal/samples/hello/README.md +++ b/core/src/main/java/io/temporal/samples/hello/README.md @@ -34,4 +34,5 @@ To run each hello world sample, use one of the following commands: ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSideEffect ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloUpdate ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignalWithTimer +./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignalWithStartAndWorkflowInit ``` diff --git a/core/src/test/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInitTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInitTest.java new file mode 100644 index 000000000..210967b28 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInitTest.java @@ -0,0 +1,76 @@ +package io.temporal.samples.hello; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkflowImplementationOptions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class HelloSignalWithStartAndWorkflowInitTest { + @RegisterExtension + public static final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + .registerWorkflowImplementationTypes( + HelloSignalWithStartAndWorkflowInit.WithInitMyWorkflowImpl.class) + .registerWorkflowImplementationTypes( + WorkflowImplementationOptions.newBuilder() + .setFailWorkflowExceptionTypes(NullPointerException.class) + .build(), + HelloSignalWithStartAndWorkflowInit.WithoutInitMyWorkflowImpl.class) + .setActivityImplementations( + new HelloSignalWithStartAndWorkflowInit.MyGreetingActivitiesImpl()) + .build(); + + @Test + public void testWithInit(TestWorkflowEnvironment testEnv, Worker worker) { + HelloSignalWithStartAndWorkflowInit.MyWorkflowWithInit withInitStub = + testEnv + .getWorkflowClient() + .newWorkflowStub( + HelloSignalWithStartAndWorkflowInit.MyWorkflowWithInit.class, + WorkflowOptions.newBuilder() + .setWorkflowId("with-init") + .setTaskQueue(worker.getTaskQueue()) + .build()); + WorkflowStub.fromTyped(withInitStub) + .signalWithStart( + "addGreeting", + new Object[] {new HelloSignalWithStartAndWorkflowInit.Person("Michael", "Jordan", 55)}, + new Object[] {new HelloSignalWithStartAndWorkflowInit.Person("John", "Stockton", 57)}); + String result = WorkflowStub.fromTyped(withInitStub).getResult(String.class); + assertEquals("Hello Michael Jordan,Hello John Stockton", result); + } + + @Test + public void testWithoutInit(TestWorkflowEnvironment testEnv, Worker worker) { + HelloSignalWithStartAndWorkflowInit.MyWorkflowNoInit noInitStub = + testEnv + .getWorkflowClient() + .newWorkflowStub( + HelloSignalWithStartAndWorkflowInit.MyWorkflowNoInit.class, + WorkflowOptions.newBuilder() + .setWorkflowId("without-init") + .setTaskQueue(worker.getTaskQueue()) + .build()); + WorkflowStub.fromTyped(noInitStub) + .signalWithStart( + "addGreeting", + new Object[] {new HelloSignalWithStartAndWorkflowInit.Person("Michael", "Jordan", 55)}, + new Object[] {new HelloSignalWithStartAndWorkflowInit.Person("John", "Stockton", 57)}); + try { + WorkflowStub.fromTyped(noInitStub).getResult(String.class); + fail("Workflow execution should have failed"); + } catch (Exception e) { + if (!(e instanceof WorkflowFailedException)) { + fail("Workflow execution should have failed with WorkflowFailedException"); + } + } + } +} From 53b769b4159fc248cf7a3fa42c4c7f3a2a17327a Mon Sep 17 00:00:00 2001 From: Tihomir Surdilovic Date: Tue, 12 Aug 2025 09:20:34 -0400 Subject: [PATCH 227/240] test for updatewithstart and cancellation (#750) Signed-off-by: Tihomir Surdilovic --- .../hello/HelloUpdateAndCancellationTest.java | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 core/src/test/java/io/temporal/samples/hello/HelloUpdateAndCancellationTest.java diff --git a/core/src/test/java/io/temporal/samples/hello/HelloUpdateAndCancellationTest.java b/core/src/test/java/io/temporal/samples/hello/HelloUpdateAndCancellationTest.java new file mode 100644 index 000000000..b6eec1fec --- /dev/null +++ b/core/src/test/java/io/temporal/samples/hello/HelloUpdateAndCancellationTest.java @@ -0,0 +1,210 @@ +package io.temporal.samples.hello; + +import io.temporal.activity.*; +import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; +import io.temporal.client.*; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.CanceledFailure; +import io.temporal.testing.TestWorkflowRule; +import io.temporal.workflow.*; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class HelloUpdateAndCancellationTest { + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setWorkflowTypes(TestWorkflowImpl.class) + .setActivityImplementations(new TestActivitiesImpl()) + .build(); + + @Test + public void testUpdateAndWorkflowCancellation() { + // Start workflow with UpdateWithStart then cancel workflow before activity completes + TestWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId("test-workflow-cancel") + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowIdConflictPolicy( + WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) + .build()); + + WorkflowUpdateHandle updateHandle = + WorkflowClient.startUpdateWithStart( + workflow::mileStoneCompleted, + UpdateOptions.newBuilder() + .setWaitForStage(WorkflowUpdateStage.ACCEPTED) + .build(), + new WithStartWorkflowOperation<>(workflow::execute)); + + testWorkflowRule + .getTestEnvironment() + .registerDelayedCallback( + Duration.ofSeconds(3), + () -> { + WorkflowStub.fromTyped(workflow).cancel("canceled by test"); + }); + + String updateResult = updateHandle.getResult(); + Assert.assertEquals("milestone canceled", updateResult); + + try { + WorkflowStub.fromTyped(workflow).getResult(String.class); + Assert.fail("Workflow Execution should have been canceled"); + } catch (WorkflowFailedException e) { + // Our workflow should have been canceled + Assert.assertEquals(CanceledFailure.class, e.getCause().getClass()); + } + } + + @Test + public void testUpdateAndActivityCancellation() { + // Start workflow with UpdateWithStart then cancel the activity only by sending signal to + // execution + TestWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestWorkflow.class, + WorkflowOptions.newBuilder() + .setWorkflowId("test-activity-cancel") + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowIdConflictPolicy( + WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) + .build()); + + WorkflowUpdateHandle updateHandle = + WorkflowClient.startUpdateWithStart( + workflow::mileStoneCompleted, + UpdateOptions.newBuilder() + .setWaitForStage(WorkflowUpdateStage.ACCEPTED) + .build(), + new WithStartWorkflowOperation<>(workflow::execute)); + + testWorkflowRule + .getTestEnvironment() + .registerDelayedCallback( + Duration.ofSeconds(3), + () -> { + WorkflowStub.fromTyped(workflow).signal("cancelActivity"); + }); + + String updateResult = updateHandle.getResult(); + Assert.assertEquals("milestone canceled", updateResult); + + try { + WorkflowStub.fromTyped(workflow).getResult(String.class); + Assert.fail("Workflow Execution should have failed"); + } catch (WorkflowFailedException e) { + // In this case we did not cancel workflow execution but we failed it by throwing + // ActivityFailure + Assert.assertEquals(ActivityFailure.class, e.getCause().getClass()); + ActivityFailure af = (ActivityFailure) e.getCause(); + // Since we canceled the activity still, the cause of ActivityFailure should be + // CanceledFailure + Assert.assertEquals(CanceledFailure.class, af.getCause().getClass()); + } + } + + @WorkflowInterface + public interface TestWorkflow { + @WorkflowMethod + String execute(); + + @UpdateMethod + String mileStoneCompleted(); + + @SignalMethod + void cancelActivity(); + } + + public static class TestWorkflowImpl implements TestWorkflow { + boolean milestoneDone, mileStoneCanceled; + CancellationScope scope; + TestActivities activities = + Workflow.newActivityStub( + TestActivities.class, + ActivityOptions.newBuilder() + .setHeartbeatTimeout(Duration.ofSeconds(3)) + .setStartToCloseTimeout(Duration.ofSeconds(10)) + .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED) + .build()); + + @Override + public String execute() { + scope = + Workflow.newCancellationScope( + () -> { + activities.runActivity(); + }); + + try { + scope.run(); + milestoneDone = true; + Workflow.await(Workflow::isEveryHandlerFinished); + return "workflow completed"; + } catch (ActivityFailure e) { + if (e.getCause() instanceof CanceledFailure) { + CancellationScope detached = + Workflow.newDetachedCancellationScope( + () -> { + mileStoneCanceled = true; + Workflow.await(Workflow::isEveryHandlerFinished); + }); + detached.run(); + } + throw e; + } + } + + @Override + public String mileStoneCompleted() { + Workflow.await(() -> milestoneDone || mileStoneCanceled); + // For sake of testing isEveryHandlerFinished block here for 2 seconds + Workflow.sleep(Duration.ofSeconds(2)); + return milestoneDone ? "milestone completed" : "milestone canceled"; + } + + @Override + public void cancelActivity() { + if (scope != null) { + scope.cancel("test reason"); + } + } + } + + @ActivityInterface + public interface TestActivities { + void runActivity(); + } + + public static class TestActivitiesImpl implements TestActivities { + + @Override + public void runActivity() { + ActivityExecutionContext context = Activity.getExecutionContext(); + for (int i = 0; i < 9; i++) { + sleep(1); + try { + context.heartbeat(i); + } catch (ActivityCompletionException e) { + throw e; + } + } + } + } + + private static void sleep(int seconds) { + try { + Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); + } catch (InterruptedException e) { + } + } +} From 0dbfe22c1156a4848c0f34a6a9f43b41a5bade86 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 25 Aug 2025 13:53:07 -0700 Subject: [PATCH 228/240] Update Java SDK to v1.31.0 (#752) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a7ece2dce..8500fb315 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.30.1' + javaSDKVersion = '1.31.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } From 626bf032cd168ffd353305a7662c2e72f6bc0ce1 Mon Sep 17 00:00:00 2001 From: Spencer Judge Date: Wed, 17 Sep 2025 16:11:57 -0700 Subject: [PATCH 229/240] Create worker deployment based versioning sample (#754) --- .gitignore | 3 +- README.md | 3 +- .../samples/workerversioning/Activities.java | 38 ++++ .../workerversioning/ActivitiesImpl.java | 25 +++ .../AutoUpgradingWorkflow.java | 15 ++ .../AutoUpgradingWorkflowV1Impl.java | 52 ++++++ .../AutoUpgradingWorkflowV1bImpl.java | 65 +++++++ .../workerversioning/PinnedWorkflow.java | 15 ++ .../PinnedWorkflowV1Impl.java | 49 ++++++ .../PinnedWorkflowV2Impl.java | 51 ++++++ .../samples/workerversioning/README.md | 26 +++ .../samples/workerversioning/Starter.java | 163 ++++++++++++++++++ .../samples/workerversioning/WorkerV1.java | 38 ++++ .../samples/workerversioning/WorkerV1_1.java | 38 ++++ .../samples/workerversioning/WorkerV2.java | 38 ++++ 15 files changed, 617 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/Activities.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/ActivitiesImpl.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1Impl.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1bImpl.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflow.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV1Impl.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV2Impl.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/README.md create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/Starter.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java create mode 100644 core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java diff --git a/.gitignore b/.gitignore index a560c2465..038d5ef43 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ target .project .settings/ bin/ -core/.vscode/ \ No newline at end of file +core/.vscode/ +.claude/ diff --git a/README.md b/README.md index a62ed4c98..15e12b8e2 100644 --- a/README.md +++ b/README.md @@ -108,8 +108,9 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Custom Annotation**](/core/src/main/java/io/temporal/samples/customannotation): Demonstrates how to create a custom annotation using an interceptor. -- [**Asnyc Packet Delivery**](/core/src/main/java/io/temporal/samples/packetdelivery): Demonstrates running multiple execution paths async within single execution. +- [**Async Packet Delivery**](/core/src/main/java/io/temporal/samples/packetdelivery): Demonstrates running multiple execution paths async within single execution. +- [**Worker Versioning**](/core/src/main/java/io/temporal/samples/workerversioning): Demonstrates how to use worker versioning to manage workflow code changes. #### API demonstrations diff --git a/core/src/main/java/io/temporal/samples/workerversioning/Activities.java b/core/src/main/java/io/temporal/samples/workerversioning/Activities.java new file mode 100644 index 000000000..b41189d2a --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/Activities.java @@ -0,0 +1,38 @@ +package io.temporal.samples.workerversioning; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; + +@ActivityInterface +public interface Activities { + + @ActivityMethod + String someActivity(String calledBy); + + @ActivityMethod + String someIncompatibleActivity(IncompatibleActivityInput input); + + class IncompatibleActivityInput { + private final String calledBy; + private final String moreData; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public IncompatibleActivityInput( + @JsonProperty("calledBy") String calledBy, @JsonProperty("moreData") String moreData) { + this.calledBy = calledBy; + this.moreData = moreData; + } + + @JsonProperty("calledBy") + public String getCalledBy() { + return calledBy; + } + + @JsonProperty("moreData") + public String getMoreData() { + return moreData; + } + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/ActivitiesImpl.java b/core/src/main/java/io/temporal/samples/workerversioning/ActivitiesImpl.java new file mode 100644 index 000000000..b3e4e2c28 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/ActivitiesImpl.java @@ -0,0 +1,25 @@ +package io.temporal.samples.workerversioning; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ActivitiesImpl implements Activities { + + private static final Logger logger = LoggerFactory.getLogger(ActivitiesImpl.class); + + @Override + public String someActivity(String calledBy) { + logger.info("SomeActivity called by {}", calledBy); + return "SomeActivity called by " + calledBy; + } + + @Override + public String someIncompatibleActivity(IncompatibleActivityInput input) { + logger.info( + "SomeIncompatibleActivity called by {} with {}", input.getCalledBy(), input.getMoreData()); + return "SomeIncompatibleActivity called by " + + input.getCalledBy() + + " with " + + input.getMoreData(); + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflow.java b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflow.java new file mode 100644 index 000000000..8dff5f7cd --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflow.java @@ -0,0 +1,15 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface AutoUpgradingWorkflow { + + @WorkflowMethod + void run(); + + @SignalMethod + void doNextSignal(String signal); +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1Impl.java b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1Impl.java new file mode 100644 index 000000000..645f0f70d --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1Impl.java @@ -0,0 +1,52 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.VersioningBehavior; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowVersioningBehavior; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; + +/** + * This workflow will automatically move to the latest worker version. We'll be making changes to + * it, which must be replay safe. Note that generally you won't want or need to include a version + * number in your workflow name if you're using the worker versioning feature. This sample does it + * to illustrate changes to the same code over time - but really what we're demonstrating here is + * the evolution of what would have been one workflow definition. + */ +public class AutoUpgradingWorkflowV1Impl implements AutoUpgradingWorkflow { + + private static final Logger logger = Workflow.getLogger(AutoUpgradingWorkflowV1Impl.class); + + private final List signals = new ArrayList<>(); + private final Activities activities = + Workflow.newActivityStub( + Activities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build()); + + @Override + @WorkflowVersioningBehavior(VersioningBehavior.AUTO_UPGRADE) + public void run() { + logger.info("Changing workflow v1 started. StartTime: {}", Workflow.currentTimeMillis()); + + while (true) { + Workflow.await(() -> !signals.isEmpty()); + String signal = signals.remove(0); + + if ("do-activity".equals(signal)) { + logger.info("Changing workflow v1 running activity"); + activities.someActivity("v1"); + } else { + logger.info("Concluding workflow v1"); + return; + } + } + } + + @Override + public void doNextSignal(String signal) { + signals.add(signal); + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1bImpl.java b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1bImpl.java new file mode 100644 index 000000000..abedf8517 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1bImpl.java @@ -0,0 +1,65 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.VersioningBehavior; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowVersioningBehavior; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; + +/** + * This represents us having made *compatible* changes to AutoUpgradingWorkflowV1Impl. + * + *

The compatible changes we've made are: + * + *

    + *
  • Altering the log lines + *
  • Using the `Workflow.getVersion` API to properly introduce branching behavior while + * maintaining compatibility + *
+ */ +public class AutoUpgradingWorkflowV1bImpl implements AutoUpgradingWorkflow { + + private static final Logger logger = Workflow.getLogger(AutoUpgradingWorkflowV1bImpl.class); + + private final List signals = new ArrayList<>(); + private final Activities activities = + Workflow.newActivityStub( + Activities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build()); + + @Override + @WorkflowVersioningBehavior(VersioningBehavior.AUTO_UPGRADE) + public void run() { + logger.info("Changing workflow v1b started. StartTime: {}", Workflow.currentTimeMillis()); + + while (true) { + Workflow.await(() -> !signals.isEmpty()); + String signal = signals.remove(0); + + if ("do-activity".equals(signal)) { + logger.info("Changing workflow v1b running activity"); + int version = Workflow.getVersion("DifferentActivity", Workflow.DEFAULT_VERSION, 1); + if (version == 1) { + activities.someIncompatibleActivity( + new Activities.IncompatibleActivityInput("v1b", "hello!")); + } else { + // Note it is a valid compatible change to alter the input to an activity. + // However, because we're using the getVersion API, this branch will never be + // taken. + activities.someActivity("v1b"); + } + } else { + logger.info("Concluding workflow v1b"); + break; + } + } + } + + @Override + public void doNextSignal(String signal) { + signals.add(signal); + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflow.java b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflow.java new file mode 100644 index 000000000..1d930a40e --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflow.java @@ -0,0 +1,15 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface PinnedWorkflow { + + @WorkflowMethod + void run(); + + @SignalMethod + void doNextSignal(String signal); +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV1Impl.java b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV1Impl.java new file mode 100644 index 000000000..4826f715c --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV1Impl.java @@ -0,0 +1,49 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.VersioningBehavior; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowVersioningBehavior; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; + +/** + * This workflow represents one that likely has a short lifetime, and we want to always stay pinned + * to the same version it began on. Note that generally you won't want or need to include a version + * number in your workflow name if you're using the worker versioning feature. This sample does it + * to illustrate changes to the same code over time - but really what we're demonstrating here is + * the evolution of what would have been one workflow definition. + */ +public class PinnedWorkflowV1Impl implements PinnedWorkflow { + + private static final Logger logger = Workflow.getLogger(PinnedWorkflowV1Impl.class); + + private final List signals = new ArrayList<>(); + private final Activities activities = + Workflow.newActivityStub( + Activities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build()); + + @Override + @WorkflowVersioningBehavior(VersioningBehavior.PINNED) + public void run() { + logger.info("Pinned Workflow v1 started. StartTime: {}", Workflow.currentTimeMillis()); + + while (true) { + Workflow.await(() -> !signals.isEmpty()); + String signal = signals.remove(0); + if ("conclude".equals(signal)) { + break; + } + } + + activities.someActivity("Pinned-v1"); + } + + @Override + public void doNextSignal(String signal) { + signals.add(signal); + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV2Impl.java b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV2Impl.java new file mode 100644 index 000000000..a880b2dc1 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV2Impl.java @@ -0,0 +1,51 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.VersioningBehavior; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowVersioningBehavior; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; + +/** + * This workflow has changes that would make it incompatible with v1, and aren't protected by a + * patch. + */ +public class PinnedWorkflowV2Impl implements PinnedWorkflow { + + private static final Logger logger = Workflow.getLogger(PinnedWorkflowV2Impl.class); + + private final List signals = new ArrayList<>(); + private final Activities activities = + Workflow.newActivityStub( + Activities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build()); + + @Override + @WorkflowVersioningBehavior(VersioningBehavior.PINNED) + public void run() { + logger.info("Pinned Workflow v2 started. StartTime: {}", Workflow.currentTimeMillis()); + + // Here we call an activity where we didn't before, which is an incompatible change. + activities.someActivity("Pinned-v2"); + + while (true) { + Workflow.await(() -> !signals.isEmpty()); + String signal = signals.remove(0); + if ("conclude".equals(signal)) { + break; + } + } + + // We've also changed the activity type here, another incompatible change + activities.someIncompatibleActivity( + new Activities.IncompatibleActivityInput("Pinned-v2", "hi")); + } + + @Override + public void doNextSignal(String signal) { + signals.add(signal); + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/README.md b/core/src/main/java/io/temporal/samples/workerversioning/README.md new file mode 100644 index 000000000..c74b10488 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/README.md @@ -0,0 +1,26 @@ +# Worker Versioning + +This sample demonstrates how to use Temporal's Worker Versioning feature to safely deploy updates to workflow and activity code. It shows the difference between auto-upgrading and pinned workflows, and how to manage worker deployments with different build IDs. + +The sample creates multiple worker versions (1.0, 1.1, and 2.0) within one deployment and demonstrates: +- **Auto-upgrading workflows**: Automatically and controllably migrate to newer worker versions +- **Pinned workflows**: Stay on the original worker version throughout their lifecycle +- **Compatible vs incompatible changes**: How to make safe updates using `Workflow.getVersion` + +## Steps to run this sample: + +1) Run a [Temporal service](https://github.com/temporalio/samples-java/tree/main/#how-to-use). And + ensure that you're using at least Server version 1.28.0 (CLI version 1.4.0). + +2) Start the main application (this will guide you through the sample): + ```bash + ./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.Starter + ``` +3) Follow the prompts to start workers in separate terminals: + - When prompted, run: `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV1` + - When prompted, run: `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV1_1` + - When prompted, run: `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV2` + +Follow the prompts in the example to observe auto-upgrading workflows migrating to newer workers +while pinned workflows remain on their original versions. + diff --git a/core/src/main/java/io/temporal/samples/workerversioning/Starter.java b/core/src/main/java/io/temporal/samples/workerversioning/Starter.java new file mode 100644 index 000000000..a48902557 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/Starter.java @@ -0,0 +1,163 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.api.workflowservice.v1.DescribeWorkerDeploymentRequest; +import io.temporal.api.workflowservice.v1.DescribeWorkerDeploymentResponse; +import io.temporal.api.workflowservice.v1.SetWorkerDeploymentCurrentVersionRequest; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.serviceclient.WorkflowServiceStubs; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Starter { + public static final String TASK_QUEUE = "worker-versioning"; + public static final String DEPLOYMENT_NAME = "my-deployment"; + + private static final Logger logger = LoggerFactory.getLogger(Starter.class); + + public static void main(String[] args) throws Exception { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + // Wait for v1 worker and set as current version + logger.info( + "Waiting for v1 worker to appear. Run `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV1` in another terminal"); + waitForWorkerAndMakeCurrent(client, service, "1.0"); + + // Start auto-upgrading and pinned workflows. Importantly, note that when we start the + // workflows, + // we are using a workflow type name which does *not* include the version number. We defined + // them + // with versioned names so we could show changes to the code, but here when the client invokes + // them, we're demonstrating that the client remains version-agnostic. + String autoUpgradeWorkflowId = "worker-versioning-versioning-autoupgrade_" + UUID.randomUUID(); + WorkflowStub autoUpgradeExecution = + client.newUntypedWorkflowStub( + "AutoUpgradingWorkflow", + WorkflowOptions.newBuilder() + .setWorkflowId(autoUpgradeWorkflowId) + .setTaskQueue(TASK_QUEUE) + .build()); + + String pinnedWorkflowId = "worker-versioning-versioning-pinned_" + UUID.randomUUID(); + WorkflowStub pinnedExecution = + client.newUntypedWorkflowStub( + "PinnedWorkflow", + WorkflowOptions.newBuilder() + .setWorkflowId(pinnedWorkflowId) + .setTaskQueue(TASK_QUEUE) + .build()); + + // Start workflows asynchronously + autoUpgradeExecution.start(); + pinnedExecution.start(); + + logger.info( + "Started auto-upgrading workflow: {}", autoUpgradeExecution.getExecution().getWorkflowId()); + logger.info("Started pinned workflow: {}", pinnedExecution.getExecution().getWorkflowId()); + + // Signal both workflows a few times to drive them + advanceWorkflows(autoUpgradeExecution, pinnedExecution); + + // Now wait for the v1.1 worker to appear and become current + logger.info( + "Waiting for v1.1 worker to appear. Run `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV1_1` in another terminal"); + waitForWorkerAndMakeCurrent(client, service, "1.1"); + + // Once it has, we will continue to advance the workflows. + // The auto-upgrade workflow will now make progress on the new worker, while the pinned one will + // keep progressing on the old worker. + advanceWorkflows(autoUpgradeExecution, pinnedExecution); + + // Finally we'll start the v2 worker, and again it'll become the new current version + logger.info( + "Waiting for v2 worker to appear. Run `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV2` in another terminal"); + waitForWorkerAndMakeCurrent(client, service, "2.0"); + + // Once it has we'll start one more new workflow, another pinned one, to demonstrate that new + // pinned workflows start on the current version. + String pinnedWorkflow2Id = "worker-versioning-versioning-pinned-2_" + UUID.randomUUID(); + WorkflowStub pinnedExecution2 = + client.newUntypedWorkflowStub( + "PinnedWorkflow", + WorkflowOptions.newBuilder() + .setWorkflowId(pinnedWorkflow2Id) + .setTaskQueue(TASK_QUEUE) + .build()); + pinnedExecution2.start(); + logger.info("Started pinned workflow v2: {}", pinnedExecution2.getExecution().getWorkflowId()); + + // Now we'll conclude all workflows. You should be able to see in your server UI that the pinned + // workflow always stayed on 1.0, while the auto-upgrading workflow migrated. + autoUpgradeExecution.signal("doNextSignal", "conclude"); + pinnedExecution.signal("doNextSignal", "conclude"); + pinnedExecution2.signal("doNextSignal", "conclude"); + + // Wait for all workflows to complete + autoUpgradeExecution.getResult(Void.class); + pinnedExecution.getResult(Void.class); + pinnedExecution2.getResult(Void.class); + + logger.info("All workflows completed"); + } + + private static void advanceWorkflows( + WorkflowStub autoUpgradeExecution, WorkflowStub pinnedExecution) { + // Signal both workflows a few times to drive them + for (int i = 0; i < 3; i++) { + autoUpgradeExecution.signal("doNextSignal", "do-activity"); + pinnedExecution.signal("doNextSignal", "some-signal"); + } + } + + private static void waitForWorkerAndMakeCurrent( + WorkflowClient client, WorkflowServiceStubs service, String buildId) + throws InterruptedException { + WorkerDeploymentVersion targetVersion = new WorkerDeploymentVersion(DEPLOYMENT_NAME, buildId); + + // Wait for the worker to appear + while (true) { + try { + DescribeWorkerDeploymentRequest describeRequest = + DescribeWorkerDeploymentRequest.newBuilder() + .setNamespace(client.getOptions().getNamespace()) + .setDeploymentName(DEPLOYMENT_NAME) + .build(); + + DescribeWorkerDeploymentResponse response = + service.blockingStub().describeWorkerDeployment(describeRequest); + + // Check if our version is present in the version summaries + boolean found = + response.getWorkerDeploymentInfo().getVersionSummariesList().stream() + .anyMatch( + versionSummary -> + targetVersion + .getDeploymentName() + .equals(versionSummary.getDeploymentVersion().getDeploymentName()) + && targetVersion + .getBuildId() + .equals(versionSummary.getDeploymentVersion().getBuildId())); + + if (found) { + break; + } + } catch (Exception ignored) { + } + Thread.sleep(1000); + } + + // Once the version is available, set it as current + SetWorkerDeploymentCurrentVersionRequest setRequest = + SetWorkerDeploymentCurrentVersionRequest.newBuilder() + .setNamespace(client.getOptions().getNamespace()) + .setDeploymentName(DEPLOYMENT_NAME) + .setBuildId(targetVersion.getBuildId()) + .build(); + + service.blockingStub().setWorkerDeploymentCurrentVersion(setRequest); + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java new file mode 100644 index 000000000..6d90b82fd --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java @@ -0,0 +1,38 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.client.WorkflowClient; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerDeploymentOptions; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WorkerV1 { + + private static final Logger logger = LoggerFactory.getLogger(WorkerV1.class); + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "1.0"); + WorkerDeploymentOptions deploymentOptions = + WorkerDeploymentOptions.newBuilder().setUseVersioning(true).setVersion(version).build(); + + WorkerOptions workerOptions = + WorkerOptions.newBuilder().setDeploymentOptions(deploymentOptions).build(); + + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(Starter.TASK_QUEUE, workerOptions); + + worker.registerWorkflowImplementationTypes( + AutoUpgradingWorkflowV1Impl.class, PinnedWorkflowV1Impl.class); + worker.registerActivitiesImplementations(new ActivitiesImpl()); + + logger.info("Starting worker v1 (build 1.0)"); + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java new file mode 100644 index 000000000..5b1235460 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java @@ -0,0 +1,38 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.client.WorkflowClient; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerDeploymentOptions; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WorkerV1_1 { + + private static final Logger logger = LoggerFactory.getLogger(WorkerV1_1.class); + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "1.1"); + WorkerDeploymentOptions deploymentOptions = + WorkerDeploymentOptions.newBuilder().setUseVersioning(true).setVersion(version).build(); + + WorkerOptions workerOptions = + WorkerOptions.newBuilder().setDeploymentOptions(deploymentOptions).build(); + + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(Starter.TASK_QUEUE, workerOptions); + + worker.registerWorkflowImplementationTypes( + AutoUpgradingWorkflowV1bImpl.class, PinnedWorkflowV1Impl.class); + worker.registerActivitiesImplementations(new ActivitiesImpl()); + + logger.info("Starting worker v1.1 (build 1.1)"); + factory.start(); + } +} diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java new file mode 100644 index 000000000..57edd0ed3 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java @@ -0,0 +1,38 @@ +package io.temporal.samples.workerversioning; + +import io.temporal.client.WorkflowClient; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerDeploymentOptions; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WorkerV2 { + + private static final Logger logger = LoggerFactory.getLogger(WorkerV2.class); + + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "2.0"); + WorkerDeploymentOptions deploymentOptions = + WorkerDeploymentOptions.newBuilder().setUseVersioning(true).setVersion(version).build(); + + WorkerOptions workerOptions = + WorkerOptions.newBuilder().setDeploymentOptions(deploymentOptions).build(); + + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(Starter.TASK_QUEUE, workerOptions); + + worker.registerWorkflowImplementationTypes( + AutoUpgradingWorkflowV1bImpl.class, PinnedWorkflowV2Impl.class); + worker.registerActivitiesImplementations(new ActivitiesImpl()); + + logger.info("Starting worker v2 (build 2.0)"); + factory.start(); + } +} From 175216aad6fc4749a33e8d30c7f8738ffb71155e Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Fri, 28 Nov 2025 09:57:11 -0800 Subject: [PATCH 230/240] Update Java SDK to v1.32.0 (#759) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8500fb315..0377d028e 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.31.0' + javaSDKVersion = '1.32.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } From c93875b3a7d220a021f0b7af931e5e3917de798a Mon Sep 17 00:00:00 2001 From: Thomas Hardy Date: Sat, 29 Nov 2025 00:15:52 -0500 Subject: [PATCH 231/240] Standalone Client Environment Configuration Sample (#755) * env config sample * update temporal-envconfig dep --- README.md | 3 + core/build.gradle | 3 + .../samples/envconfig/LoadFromFile.java | 79 +++++++++++++++++ .../samples/envconfig/LoadProfile.java | 87 +++++++++++++++++++ .../io/temporal/samples/envconfig/README.md | 18 ++++ core/src/main/resources/config.toml | 40 +++++++++ 6 files changed, 230 insertions(+) create mode 100644 core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java create mode 100644 core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java create mode 100644 core/src/main/java/io/temporal/samples/envconfig/README.md create mode 100644 core/src/main/resources/config.toml diff --git a/README.md b/README.md index 15e12b8e2..4d00e320b 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,9 @@ See the README.md file in each main sample directory for cut/paste Gradle comman - [**Worker Versioning**](/core/src/main/java/io/temporal/samples/workerversioning): Demonstrates how to use worker versioning to manage workflow code changes. +- [**Environment Configuration**](/core/src/main/java/io/temporal/samples/envconfig): +Load client configuration from TOML files with programmatic overrides. + #### API demonstrations - [**Async Untyped Child Workflow**](/core/src/main/java/io/temporal/samples/asyncuntypedchild): Demonstrates how to invoke an untyped child workflow async, that can complete after parent workflow is already completed. diff --git a/core/build.gradle b/core/build.gradle index 42ad4be2b..62fbfa8e9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -4,6 +4,9 @@ dependencies { implementation "io.temporal:temporal-opentracing:$javaSDKVersion" testImplementation("io.temporal:temporal-testing:$javaSDKVersion") + // Environment configuration + implementation "io.temporal:temporal-envconfig:$javaSDKVersion" + // Needed for SDK related functionality implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.2")) implementation "com.fasterxml.jackson.core:jackson-databind" diff --git a/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java b/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java new file mode 100644 index 000000000..b6a9f7187 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java @@ -0,0 +1,79 @@ +package io.temporal.samples.envconfig; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.envconfig.ClientConfigProfile; +import io.temporal.envconfig.LoadClientConfigProfileOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import java.nio.file.Paths; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This sample demonstrates loading the default environment configuration profile from a TOML file. + */ +public class LoadFromFile { + + private static final Logger logger = LoggerFactory.getLogger(LoadFromFile.class); + + public static void main(String[] args) { + try { + // For this sample to be self-contained, we explicitly provide the path to + // the config.toml file included in this directory. + // By default though, the config.toml file will be loaded from + // ~/.config/temporal/temporal.toml (or the equivalent standard config directory on your OS). + String configFilePath = + Paths.get(LoadFromFile.class.getResource("/config.toml").toURI()).toString(); + + logger.info("--- Loading 'default' profile from {} ---", configFilePath); + + // Load client profile from file. By default, this loads the "default" profile + // and applies any environment variable overrides. + ClientConfigProfile profile = + ClientConfigProfile.load( + LoadClientConfigProfileOptions.newBuilder() + .setConfigFilePath(configFilePath) + .build()); + + // Convert profile to client options (equivalent to Python's load_client_connect_config) + WorkflowServiceStubsOptions serviceStubsOptions = profile.toWorkflowServiceStubsOptions(); + WorkflowClientOptions clientOptions = profile.toWorkflowClientOptions(); + + logger.info("Loaded 'default' profile from {}", configFilePath); + logger.info(" Address: {}", serviceStubsOptions.getTarget()); + logger.info(" Namespace: {}", clientOptions.getNamespace()); + if (serviceStubsOptions.getHeaders() != null + && !serviceStubsOptions.getHeaders().keys().isEmpty()) { + logger.info(" gRPC Metadata keys: {}", serviceStubsOptions.getHeaders().keys()); + } + + logger.info("\nAttempting to connect to client..."); + + try { + // Create the workflow client using the loaded configuration + WorkflowClient client = + WorkflowClient.newInstance( + WorkflowServiceStubs.newServiceStubs(serviceStubsOptions), clientOptions); + + // Test the connection by getting system info + var systemInfo = + client + .getWorkflowServiceStubs() + .blockingStub() + .getSystemInfo( + io.temporal.api.workflowservice.v1.GetSystemInfoRequest.getDefaultInstance()); + + logger.info("βœ… Client connected successfully!"); + logger.info(" Server version: {}", systemInfo.getServerVersion()); + + } catch (Exception e) { + logger.error("❌ Failed to connect: {}", e.getMessage()); + } + + } catch (Exception e) { + logger.error("Failed to load configuration: {}", e.getMessage(), e); + System.exit(1); + } + } +} diff --git a/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java b/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java new file mode 100644 index 000000000..9d05b21f3 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java @@ -0,0 +1,87 @@ +package io.temporal.samples.envconfig; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.envconfig.ClientConfigProfile; +import io.temporal.envconfig.LoadClientConfigProfileOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import java.nio.file.Paths; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This sample demonstrates loading a specific profile from a TOML configuration file with + * programmatic overrides. + */ +public class LoadProfile { + + private static final Logger logger = LoggerFactory.getLogger(LoadProfile.class); + + public static void main(String[] args) { + String profileName = "staging"; + + try { + // For this sample to be self-contained, we explicitly provide the path to + // the config.toml file included in this directory. + String configFilePath = + Paths.get(LoadProfile.class.getResource("/config.toml").toURI()).toString(); + + logger.info("--- Loading '{}' profile from {} ---", profileName, configFilePath); + + // Load specific profile from file with environment variable overrides + ClientConfigProfile profile = + ClientConfigProfile.load( + LoadClientConfigProfileOptions.newBuilder() + .setConfigFilePath(configFilePath) + .setConfigFileProfile(profileName) + .build()); + + // Demonstrate programmatic override - fix the incorrect address from staging profile + logger.info("\n--- Applying programmatic override ---"); + ClientConfigProfile.Builder profileBuilder = profile.toBuilder(); + profileBuilder.setAddress("localhost:7233"); // Override the incorrect address + profile = profileBuilder.build(); + logger.info(" Overridden address to: {}", profile.getAddress()); + + // Convert profile to client options (equivalent to Python's load_client_connect_config) + WorkflowServiceStubsOptions serviceStubsOptions = profile.toWorkflowServiceStubsOptions(); + WorkflowClientOptions clientOptions = profile.toWorkflowClientOptions(); + + logger.info("Loaded '{}' profile from {}", profileName, configFilePath); + logger.info(" Address: {}", serviceStubsOptions.getTarget()); + logger.info(" Namespace: {}", clientOptions.getNamespace()); + if (serviceStubsOptions.getHeaders() != null + && !serviceStubsOptions.getHeaders().keys().isEmpty()) { + logger.info(" gRPC Metadata keys: {}", serviceStubsOptions.getHeaders().keys()); + } + + logger.info("\nAttempting to connect to client..."); + + try { + // Create the workflow client using the loaded configuration + WorkflowClient client = + WorkflowClient.newInstance( + WorkflowServiceStubs.newServiceStubs(serviceStubsOptions), clientOptions); + + // Test the connection by getting system info + var systemInfo = + client + .getWorkflowServiceStubs() + .blockingStub() + .getSystemInfo( + io.temporal.api.workflowservice.v1.GetSystemInfoRequest.getDefaultInstance()); + + logger.info("βœ… Client connected successfully!"); + logger.info(" Server version: {}", systemInfo.getServerVersion()); + + } catch (Exception e) { + logger.error("❌ Failed to connect: {}", e.getMessage()); + } + + } catch (Exception e) { + logger.error("Failed to load configuration: {}", e.getMessage(), e); + System.exit(1); + } + } +} diff --git a/core/src/main/java/io/temporal/samples/envconfig/README.md b/core/src/main/java/io/temporal/samples/envconfig/README.md new file mode 100644 index 000000000..0cb5df5c1 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/envconfig/README.md @@ -0,0 +1,18 @@ +# Environment Configuration Sample + +This sample demonstrates how to configure a Temporal client using TOML configuration files. This allows you to manage connection settings across different environments without hardcoding them. + +The `config.toml` file defines three profiles: +- `[profile.default]`: Local development configuration +- `[profile.staging]`: Configuration with incorrect address to demonstrate overrides +- `[profile.prod]`: Example production configuration (not runnable) + +**Load from file (default profile):** +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.envconfig.LoadFromFile +``` + +**Load specific profile with overrides:** +```bash +./gradlew -q execute -PmainClass=io.temporal.samples.envconfig.LoadProfile +``` \ No newline at end of file diff --git a/core/src/main/resources/config.toml b/core/src/main/resources/config.toml new file mode 100644 index 000000000..81f07f786 --- /dev/null +++ b/core/src/main/resources/config.toml @@ -0,0 +1,40 @@ +# This is a sample configuration file for demonstrating Temporal's environment +# configuration feature. It defines multiple profiles for different environments, +# such as local development, production, and staging. + +# Default profile for local development +[profile.default] +address = "localhost:7233" +namespace = "default" + +# Optional: Add custom gRPC headers +[profile.default.grpc_meta] +my-custom-header = "development-value" +trace-id = "dev-trace-123" + +# Staging profile with inline certificate data +[profile.staging] +address = "localhost:9999" +namespace = "staging" + +# An example production profile for Temporal Cloud +[profile.prod] +address = "your-namespace.a1b2c.tmprl.cloud:7233" +namespace = "your-namespace" +# Replace with your actual Temporal Cloud API key +api_key = "your-api-key-here" + +# TLS configuration for production +[profile.prod.tls] +# TLS is auto-enabled when an API key is present, but you can configure it +# explicitly. +# disabled = false + +# Use certificate files for mTLS. Replace with actual paths. +client_cert_path = "/etc/temporal/certs/client.pem" +client_key_path = "/etc/temporal/certs/client.key" + +# Custom headers for production +[profile.prod.grpc_meta] +environment = "production" +service-version = "v1.2.3" \ No newline at end of file From d3b90e6951aa62efd0259b427d70e91e25bef39f Mon Sep 17 00:00:00 2001 From: Thomas Hardy Date: Thu, 4 Dec 2025 11:25:35 -0800 Subject: [PATCH 232/240] Update samples to use env config (#756) * Update samples to use env config * fix envconfig import for springboot * update javaSDKVersion to 1.32.1 --- build.gradle | 2 +- .../temporal/samples/apikey/ApiKeyWorker.java | 19 ++++++++++-- .../io/temporal/samples/apikey/Starter.java | 19 ++++++++++-- .../temporal/samples/asyncchild/Starter.java | 31 ++++++++++++++----- .../samples/asyncuntypedchild/Starter.java | 15 +++++++-- .../samples/autoheartbeat/Starter.java | 15 +++++++-- .../HeartbeatingActivityBatchStarter.java | 16 ++++++++-- .../HeartbeatingActivityBatchWorker.java | 15 +++++++-- .../batch/iterator/IteratorBatchStarter.java | 16 ++++++++-- .../batch/iterator/IteratorBatchWorker.java | 15 +++++++-- .../SlidingWindowBatchStarter.java | 16 ++++++++-- .../SlidingWindowBatchWorker.java | 15 +++++++-- .../bookingsaga/TripBookingClient.java | 17 ++++++++-- .../bookingsaga/TripBookingWorker.java | 17 ++++++++-- .../bookingsyncsaga/TripBookingClient.java | 17 ++++++++-- .../bookingsyncsaga/TripBookingWorker.java | 15 +++++++-- .../common/QueryWorkflowExecution.java | 15 +++++++-- .../countinterceptor/InterceptorStarter.java | 13 +++++++- .../customannotation/CustomAnnotation.java | 15 +++++++-- .../CustomChangeVersionStarter.java | 15 +++++++-- .../java/io/temporal/samples/dsl/Starter.java | 19 ++++++++---- .../earlyreturn/EarlyReturnClient.java | 15 +++++++-- .../samples/encodefailures/Starter.java | 13 +++++++- .../EncryptedPayloadsActivity.java | 13 +++++++- .../RunMyWorkflows.java | 15 +++++++-- .../fileprocessing/FileProcessingStarter.java | 17 ++++++++-- .../fileprocessing/FileProcessingWorker.java | 17 ++++++++-- .../samples/getresultsasync/Worker.java | 23 ++++++++++++-- .../samples/hello/HelloAccumulator.java | 19 +++++++----- .../temporal/samples/hello/HelloActivity.java | 15 +++++++-- .../hello/HelloActivityExclusiveChoice.java | 15 +++++++-- .../samples/hello/HelloActivityRetry.java | 18 +++++++---- .../io/temporal/samples/hello/HelloAsync.java | 19 ++++++++---- .../hello/HelloAsyncActivityCompletion.java | 20 +++++++----- .../samples/hello/HelloAsyncLambda.java | 19 ++++++++---- .../io/temporal/samples/hello/HelloAwait.java | 19 ++++++++---- .../samples/hello/HelloCancellationScope.java | 19 ++++++++---- .../HelloCancellationScopeWithTimer.java | 15 +++++++-- .../io/temporal/samples/hello/HelloChild.java | 19 ++++++++---- .../io/temporal/samples/hello/HelloCron.java | 19 ++++++++---- .../samples/hello/HelloDelayedStart.java | 19 ++++++++---- .../hello/HelloDetachedCancellationScope.java | 15 +++++++-- .../temporal/samples/hello/HelloDynamic.java | 20 +++++++----- .../hello/HelloEagerWorkflowStart.java | 19 ++++++++---- .../samples/hello/HelloException.java | 18 +++++++---- .../samples/hello/HelloLocalActivity.java | 17 ++++++++-- .../samples/hello/HelloParallelActivity.java | 19 ++++++++---- .../temporal/samples/hello/HelloPeriodic.java | 19 ++++++++---- .../hello/HelloPolymorphicActivity.java | 19 ++++++++---- .../io/temporal/samples/hello/HelloQuery.java | 19 ++++++++---- .../io/temporal/samples/hello/HelloSaga.java | 19 ++++++++---- .../samples/hello/HelloSchedules.java | 19 ++++++++---- .../samples/hello/HelloSearchAttributes.java | 19 ++++++++---- .../samples/hello/HelloSideEffect.java | 20 +++++++----- .../temporal/samples/hello/HelloSignal.java | 19 ++++++++---- .../HelloSignalWithStartAndWorkflowInit.java | 15 +++++++-- .../samples/hello/HelloSignalWithTimer.java | 15 +++++++-- .../hello/HelloTypedSearchAttributes.java | 19 ++++++++---- .../temporal/samples/hello/HelloUpdate.java | 19 ++++++++---- .../samples/hello/HelloWorkflowTimer.java | 17 ++++++++-- .../awsencryptionsdk/EncryptedPayloads.java | 13 +++++++- .../samples/listworkflows/Starter.java | 20 ++++++++++-- .../samples/metrics/MetricsStarter.java | 18 +++++++++-- .../samples/metrics/MetricsWorker.java | 18 +++++++++-- .../moneybatch/AccountActivityWorker.java | 15 +++++++-- .../moneybatch/AccountTransferWorker.java | 15 +++++++-- .../samples/moneybatch/TransferRequester.java | 16 ++++++++-- .../moneytransfer/AccountActivityWorker.java | 17 ++++++++-- .../moneytransfer/AccountTransferWorker.java | 17 ++++++++-- .../moneytransfer/TransferRequester.java | 16 ++++++++-- .../samples/packetdelivery/Starter.java | 15 +++++++-- .../payloadconverter/cloudevents/Starter.java | 13 +++++++- .../payloadconverter/crypto/Starter.java | 13 +++++++- .../samples/peractivityoptions/Starter.java | 18 +++++++++-- .../frequent/FrequentPollingStarter.java | 20 ++++++++++-- .../infrequent/InfrequentPollingStarter.java | 20 ++++++++++-- ...nfrequentPollingWithRetryAfterStarter.java | 20 ++++++++++-- .../PeriodicPollingStarter.java | 20 ++++++++++-- .../FailureRequester.java | 15 +++++++-- .../MyWorkflowWorker.java | 15 +++++++-- .../QueryRequester.java | 15 +++++++-- .../RetryRequester.java | 15 +++++++-- .../ClusterManagerWorkflowStarter.java | 15 +++++++-- .../ClusterManagerWorkflowWorker.java | 15 +++++++-- .../samples/sleepfordays/Starter.java | 17 +++++++++- .../temporal/samples/sleepfordays/Worker.java | 18 +++++++++-- .../samples/terminateworkflow/Starter.java | 27 +++++++++++----- .../io/temporal/samples/tracing/Starter.java | 18 +++++++++-- .../samples/tracing/TracingWorker.java | 16 ++++++++-- .../DynamicSleepWorkflowStarter.java | 15 +++++++-- .../DynamicSleepWorkflowWorker.java | 15 +++++++-- .../updatabletimer/WakeUpTimeUpdater.java | 15 +++++++-- .../samples/workerversioning/Starter.java | 16 ++++++++-- .../samples/workerversioning/WorkerV1.java | 15 +++++++-- .../samples/workerversioning/WorkerV1_1.java | 15 +++++++-- .../samples/workerversioning/WorkerV2.java | 15 +++++++-- springboot/build.gradle | 3 ++ 97 files changed, 1313 insertions(+), 317 deletions(-) diff --git a/build.gradle b/build.gradle index 0377d028e..abb6487ba 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.32.0' + javaSDKVersion = '1.32.1' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java b/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java index 7425b88d6..2c4a326d4 100644 --- a/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java +++ b/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java @@ -2,15 +2,25 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.serviceclient.WorkflowServiceStubsOptions; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class ApiKeyWorker { static final String TASK_QUEUE = "MyTaskQueue"; public static void main(String[] args) throws Exception { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + // For temporal cloud this would be ${cloud-region}.{cloud}.api.temporal.io:7233 // Example us-east-1.aws.api.temporal.io:7233 String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT"); @@ -24,10 +34,10 @@ public static void main(String[] args) throws Exception { "TEMPORAL_ENDPOINT, TEMPORAL_NAMESPACE, and TEMPORAL_API_KEY environment variables must be set"); } - // Create API Key enabled client + // Create API Key enabled client with environment config as base WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs( - WorkflowServiceStubsOptions.newBuilder() + WorkflowServiceStubsOptions.newBuilder(profile.toWorkflowServiceStubsOptions()) .setTarget(targetEndpoint) .setEnableHttps(true) .addApiKey(() -> apiKey) @@ -36,7 +46,10 @@ public static void main(String[] args) throws Exception { // Now setup and start workflow worker WorkflowClient client = WorkflowClient.newInstance( - service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build()); + service, + WorkflowClientOptions.newBuilder(profile.toWorkflowClientOptions()) + .setNamespace(namespace) + .build()); // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/apikey/Starter.java b/core/src/main/java/io/temporal/samples/apikey/Starter.java index 60afe7c21..ac0fbce8c 100644 --- a/core/src/main/java/io/temporal/samples/apikey/Starter.java +++ b/core/src/main/java/io/temporal/samples/apikey/Starter.java @@ -3,10 +3,12 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.serviceclient.WorkflowServiceStubsOptions; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class Starter { @@ -14,6 +16,14 @@ public class Starter { static final String WORKFLOW_ID = "HelloAPIKeyWorkflow"; public static void main(String[] args) throws Exception { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + // For temporal cloud this would be ${cloud-region}.{cloud}.api.temporal.io:7233 // Example us-east-1.aws.api.temporal.io:7233 String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT"); @@ -27,10 +37,10 @@ public static void main(String[] args) throws Exception { "TEMPORAL_ENDPOINT, TEMPORAL_NAMESPACE, and TEMPORAL_API_KEY environment variables must be set"); } - // Create API Key enabled client + // Create API Key enabled client with environment config as base WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs( - WorkflowServiceStubsOptions.newBuilder() + WorkflowServiceStubsOptions.newBuilder(profile.toWorkflowServiceStubsOptions()) .setTarget(targetEndpoint) .setEnableHttps(true) .addApiKey(() -> apiKey) @@ -38,7 +48,10 @@ public static void main(String[] args) throws Exception { WorkflowClient client = WorkflowClient.newInstance( - service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build()); + service, + WorkflowClientOptions.newBuilder(profile.toWorkflowClientOptions()) + .setNamespace(namespace) + .build()); WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/asyncchild/Starter.java b/core/src/main/java/io/temporal/samples/asyncchild/Starter.java index b02f0dc4c..339bd94fd 100644 --- a/core/src/main/java/io/temporal/samples/asyncchild/Starter.java +++ b/core/src/main/java/io/temporal/samples/asyncchild/Starter.java @@ -6,20 +6,32 @@ import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionResponse; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import java.util.concurrent.TimeUnit; public class Starter { public static final String TASK_QUEUE = "asyncChildTaskQueue"; - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); - private static final WorkerFactory factory = WorkerFactory.newInstance(client); public static void main(String[] args) { - createWorker(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + WorkerFactory factory = WorkerFactory.newInstance(client); + + createWorker(factory); WorkflowOptions parentWorkflowOptions = WorkflowOptions.newBuilder() @@ -33,25 +45,28 @@ public static void main(String[] args) { WorkflowExecution childWorkflowExecution = parentWorkflowStub.executeParent(); // Get the child workflow execution status (after parent completed) - System.out.println("Child execution status: " + getStatusAsString(childWorkflowExecution)); + System.out.println( + "Child execution status: " + getStatusAsString(childWorkflowExecution, client, service)); // Wait for child workflow to complete sleep(4); // Check the status of the child workflow again - System.out.println("Child execution status: " + getStatusAsString(childWorkflowExecution)); + System.out.println( + "Child execution status: " + getStatusAsString(childWorkflowExecution, client, service)); System.exit(0); } - private static void createWorker() { + private static void createWorker(WorkerFactory factory) { Worker worker = factory.newWorker(TASK_QUEUE); worker.registerWorkflowImplementationTypes(ParentWorkflowImpl.class, ChildWorkflowImpl.class); factory.start(); } - private static String getStatusAsString(WorkflowExecution execution) { + private static String getStatusAsString( + WorkflowExecution execution, WorkflowClient client, WorkflowServiceStubs service) { DescribeWorkflowExecutionRequest describeWorkflowExecutionRequest = DescribeWorkflowExecutionRequest.newBuilder() .setNamespace(client.getOptions().getNamespace()) diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java index 6cf9da20f..885a0c05c 100644 --- a/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java +++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java @@ -2,9 +2,11 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; /** * Sample Temporal Workflow Definition that demonstrates the execution of a Child Workflow. Child @@ -24,12 +26,21 @@ public class Starter { public static void main(String[] args) { // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. */ - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java b/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java index 67bb97ec3..ae438cc41 100644 --- a/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java +++ b/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java @@ -22,6 +22,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.failure.CanceledFailure; import io.temporal.samples.autoheartbeat.activities.AutoActivitiesImpl; import io.temporal.samples.autoheartbeat.interceptor.AutoHeartbeatWorkerInterceptor; @@ -31,14 +32,24 @@ import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerFactoryOptions; +import java.io.IOException; public class Starter { static final String TASK_QUEUE = "AutoheartbeatTaskQueue"; static final String WORKFLOW_ID = "AutoHeartbeatWorkflow"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // Configure our auto heartbeat workflow interceptor which will apply // AutoHeartbeaterUtil to each activity workflow schedules which has a heartbeat diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java index 89bb5652c..90dcb7c10 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java @@ -5,14 +5,26 @@ import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; /** Starts a single execution of HeartbeatingActivityBatchWorkflow. */ public class HeartbeatingActivityBatchStarter { public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient workflowClient = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient workflowClient = + WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build(); HeartbeatingActivityBatchWorkflow batchWorkflow = workflowClient.newWorkflowStub(HeartbeatingActivityBatchWorkflow.class, options); diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java index 9d2d7b4e1..cd63bacf5 100644 --- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java +++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java @@ -1,9 +1,11 @@ package io.temporal.samples.batch.heartbeatingactivity; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; /** * A worker process that hosts implementations of HeartbeatingActivityBatchWorkflow and @@ -14,8 +16,17 @@ public final class HeartbeatingActivityBatchWorker { static final String TASK_QUEUE = "HeartbeatingActivityBatch"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker(TASK_QUEUE); diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java index c89fc590c..fa43c467f 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java @@ -5,14 +5,26 @@ import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; /** Starts a single execution of IteratorBatchWorkflow. */ public class IteratorBatchStarter { public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient workflowClient = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient workflowClient = + WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build(); IteratorBatchWorkflow batchWorkflow = workflowClient.newWorkflowStub(IteratorBatchWorkflow.class, options); diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java index 88b8eacb7..adc023d7b 100644 --- a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java +++ b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java @@ -1,9 +1,11 @@ package io.temporal.samples.batch.iterator; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; /** * A worker process that hosts implementations of IteratorBatchWorkflow and RecordProcessorWorkflow @@ -14,8 +16,17 @@ public final class IteratorBatchWorker { static final String TASK_QUEUE = "IteratorBatch"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker(TASK_QUEUE); diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java index f4d689f4a..e3a6b062d 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java @@ -4,14 +4,26 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; public class SlidingWindowBatchStarter { @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient workflowClient = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient workflowClient = + WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build(); BatchWorkflow batchWorkflow = workflowClient.newWorkflowStub(BatchWorkflow.class, options); WorkflowClient.start(batchWorkflow::processBatch, 10, 25, 3); diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java index 32dd8e09c..20caa5ead 100644 --- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java +++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java @@ -1,9 +1,11 @@ package io.temporal.samples.batch.slidingwindow; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; /** Hosts sliding window batch sample workflow and activity implementations. */ public final class SlidingWindowBatchWorker { @@ -11,8 +13,17 @@ public final class SlidingWindowBatchWorker { static final String TASK_QUEUE = "SlidingWindow"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker(TASK_QUEUE); diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java index b791065da..cb7d1e594 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java @@ -3,17 +3,28 @@ import com.google.common.base.Throwables; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; public class TripBookingClient { static final String TASK_QUEUE = "TripBooking"; public static void main(String[] args) { - // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // gRPC stubs wrapper that talks to the temporal service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId("Booking1").build(); diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java index b538e0942..6c0fb87b2 100644 --- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java +++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java @@ -1,18 +1,29 @@ package io.temporal.samples.bookingsaga; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class TripBookingWorker { @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { - // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // gRPC stubs wrapper that talks to the temporal service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java index cebbc93b8..74aa32b86 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java @@ -3,17 +3,28 @@ import com.google.common.base.Throwables; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; public class TripBookingClient { static final String TASK_QUEUE = "TripBookingSync"; public static void main(String[] args) { - // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // gRPC stubs wrapper that talks to the temporal service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId("Booking1").build(); diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java index 151bd62ae..c70dc9481 100644 --- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java +++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java @@ -1,18 +1,29 @@ package io.temporal.samples.bookingsyncsaga; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class TripBookingWorker { @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java b/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java index 9be315a8a..9f9cbe797 100644 --- a/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java +++ b/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java @@ -3,7 +3,9 @@ import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; import java.util.Optional; /** @@ -27,9 +29,18 @@ public static void main(String[] args) { String runId = args.length == 3 ? args[2] : ""; // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkflowExecution workflowExecution = WorkflowExecution.newBuilder().setWorkflowId(workflowId).setRunId(runId).build(); diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java b/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java index bf8ddd793..30c73c14f 100644 --- a/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java +++ b/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java @@ -5,6 +5,7 @@ import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.common.interceptors.WorkflowClientInterceptor; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.countinterceptor.activities.MyActivitiesImpl; import io.temporal.samples.countinterceptor.workflow.MyChildWorkflowImpl; import io.temporal.samples.countinterceptor.workflow.MyWorkflow; @@ -13,6 +14,7 @@ import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerFactoryOptions; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,7 +31,16 @@ public static void main(String[] args) { final ClientCounter clientCounter = new ClientCounter(); final WorkflowClientInterceptor clientInterceptor = new SimpleClientInterceptor(clientCounter); - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); WorkflowClient client = WorkflowClient.newInstance( service, WorkflowClientOptions.newBuilder().setInterceptors(clientInterceptor).build()); diff --git a/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java b/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java index 9f9fc667d..db6df4229 100644 --- a/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java +++ b/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java @@ -24,6 +24,7 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -31,6 +32,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; public class CustomAnnotation { @@ -132,12 +134,21 @@ public synchronized String composeGreeting(String greeting, String name) { public static void main(String[] args) { // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. */ - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java index 82921b8dc..3bd8497b7 100644 --- a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java +++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java @@ -8,22 +8,33 @@ import io.temporal.client.WorkflowServiceException; import io.temporal.common.SearchAttributeKey; import io.temporal.common.SearchAttributes; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.OperatorServiceStubs; import io.temporal.serviceclient.OperatorServiceStubsOptions; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import java.util.Collections; public class CustomChangeVersionStarter { private static SearchAttributeKey CUSTOM_CHANGE_VERSION = SearchAttributeKey.forKeyword("CustomChangeVersion"); - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); private static final String taskQueue = "customChangeVersionTaskQueue"; private static final String workflowId = "CustomChangeVersionWorkflow"; public static void main(String[] args) { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory workerFactory = WorkerFactory.newInstance(client); Worker worker = workerFactory.newWorker(taskQueue); diff --git a/core/src/main/java/io/temporal/samples/dsl/Starter.java b/core/src/main/java/io/temporal/samples/dsl/Starter.java index e0336d659..257531048 100644 --- a/core/src/main/java/io/temporal/samples/dsl/Starter.java +++ b/core/src/main/java/io/temporal/samples/dsl/Starter.java @@ -3,22 +3,29 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.dsl.model.Flow; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class Starter { - public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - public static final WorkflowClient client = WorkflowClient.newInstance(service); - public static final WorkerFactory factory = WorkerFactory.newInstance(client); - public static void main(String[] args) { Flow flow = getFlowFromResource(); - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker("dsl-task-queue"); worker.registerWorkflowImplementationTypes(DslWorkflowImpl.class); diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java index 623efa310..3abd20a7c 100644 --- a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java +++ b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java @@ -2,7 +2,9 @@ import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; import io.temporal.client.*; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; public class EarlyReturnClient { private static final String TASK_QUEUE = "EarlyReturnTaskQueue"; @@ -15,8 +17,17 @@ public static void main(String[] args) { // Set up the WorkflowClient public static WorkflowClient setupWorkflowClient() { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - return WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + return WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); } // Run workflow using 'updateWithStart' diff --git a/core/src/main/java/io/temporal/samples/encodefailures/Starter.java b/core/src/main/java/io/temporal/samples/encodefailures/Starter.java index 9e4e17fe0..f08766881 100644 --- a/core/src/main/java/io/temporal/samples/encodefailures/Starter.java +++ b/core/src/main/java/io/temporal/samples/encodefailures/Starter.java @@ -8,10 +8,12 @@ import io.temporal.client.WorkflowOptions; import io.temporal.common.converter.CodecDataConverter; import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkflowImplementationOptions; +import java.io.IOException; import java.util.Collections; public class Starter { @@ -19,7 +21,16 @@ public class Starter { private static final String WORKFLOW_ID = "CustomerValidationWorkflow"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // CodecDataConverter defines our data converter and codec // sets encodeFailureAttributes to true diff --git a/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java b/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java index 00636fb29..83f10d95c 100644 --- a/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java +++ b/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java @@ -8,12 +8,14 @@ import io.temporal.client.WorkflowOptions; import io.temporal.common.converter.CodecDataConverter; import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.util.Collections; @@ -68,7 +70,16 @@ public String composeGreeting(String greeting, String name) { public static void main(String[] args) { // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows WorkflowClient client = WorkflowClient.newInstance( diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java index b4bd1e825..4efe7d1f6 100644 --- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java +++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java @@ -3,6 +3,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.excludefrominterceptor.activities.ForInterceptorActivitiesImpl; import io.temporal.samples.excludefrominterceptor.activities.MyActivitiesImpl; import io.temporal.samples.excludefrominterceptor.interceptor.MyWorkerInterceptor; @@ -11,13 +12,23 @@ import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerFactoryOptions; +import java.io.IOException; import java.util.Arrays; import java.util.concurrent.CompletableFuture; public class RunMyWorkflows { public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactoryOptions wfo = WorkerFactoryOptions.newBuilder() diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java index f2c1ee95a..5020bf519 100644 --- a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java +++ b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java @@ -4,17 +4,28 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; import java.net.URL; /** Starts a file processing sample workflow. */ public class FileProcessingStarter { public static void main(String[] args) throws Exception { - // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // gRPC stubs wrapper that talks to the temporal service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); FileProcessingWorkflow workflow = client.newWorkflowStub( FileProcessingWorkflow.class, diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java index b154a2c23..711ca7343 100644 --- a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java +++ b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java @@ -1,9 +1,11 @@ package io.temporal.samples.fileprocessing; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import java.lang.management.ManagementFactory; /** @@ -21,10 +23,19 @@ public static void main(String[] args) { String hostSpecifiTaskQueue = ManagementFactory.getRuntimeMXBean().getName(); - // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // gRPC stubs wrapper that talks to the temporal service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java b/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java index d9bb276be..4a91026f8 100644 --- a/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java +++ b/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java @@ -1,13 +1,30 @@ package io.temporal.samples.getresultsasync; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class Worker { - public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - public static final WorkflowClient client = WorkflowClient.newInstance(service); - public static final WorkerFactory factory = WorkerFactory.newInstance(client); + public static final WorkflowServiceStubs service; + public static final WorkflowClient client; + public static final WorkerFactory factory; + + static { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + factory = WorkerFactory.newInstance(client); + } + public static final String TASK_QUEUE_NAME = "asyncstartqueue"; public static void main(String[] args) { diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java b/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java index 38ea8f097..2f8d67457 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java @@ -11,6 +11,7 @@ import io.temporal.client.WorkflowNotFoundException; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -18,6 +19,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.io.Serializable; import java.time.Duration; import java.util.ArrayDeque; @@ -293,14 +295,17 @@ public void exit() { */ public static void main(String[] args) throws Exception { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query - * Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); client.getWorkflowServiceStubs().healthCheck(); /* diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java index 3c890d3ab..9b202e0c2 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java @@ -5,12 +5,14 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -105,13 +107,22 @@ public String composeGreeting(String greeting, String name) { */ public static void main(String[] args) { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. */ - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java index 1da873e2c..3f2309993 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java @@ -4,12 +4,14 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -165,12 +167,21 @@ public static void main(String[] args) { * Define the workflow service. It is a gRPC stubs wrapper which talks to the docker instance of * our locally running Temporal service. */ - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. */ - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java index f7f01b3a3..4f78cfa2f 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java @@ -5,12 +5,14 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.common.RetryOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** Sample Temporal workflow that demonstrates workflow activity retries. */ @@ -140,13 +142,17 @@ public synchronized String composeGreeting(String greeting, String name) { */ public static void main(String[] args) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsync.java b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java index 7b068f7bf..25e8c3c5f 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsync.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java @@ -4,6 +4,7 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -12,6 +13,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** Sample Temporal Workflow Definition that demonstrates an asynchronous Activity Execution. */ @@ -110,13 +112,18 @@ public String composeGreeting(String greeting, String name) { */ public static void main(String[] args) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java index 87f9cbee7..f52072738 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java @@ -4,12 +4,14 @@ import io.temporal.client.ActivityCompletionClient; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -143,14 +145,18 @@ private void composeGreetingAsync(byte[] taskToken, String greeting, String name */ public static void main(String[] args) throws ExecutionException, InterruptedException { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow - * Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java index 4da2b6ee1..6b68d85cb 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java @@ -4,6 +4,7 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -12,6 +13,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** Sample Temporal Workflow Definition that demonstrates an asynchronous Activity Executions. */ @@ -128,13 +130,18 @@ public String composeGreeting(String greeting, String name) { */ public static void main(String[] args) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAwait.java b/core/src/main/java/io/temporal/samples/hello/HelloAwait.java index 069f5bb65..588b9e3fc 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloAwait.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloAwait.java @@ -3,6 +3,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.failure.ApplicationFailure; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; @@ -11,6 +12,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** @@ -80,13 +82,18 @@ public void waitForName(String name) { */ public static void main(String[] args) throws Exception { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Await, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java index 59cc0c7c8..c98a6fac5 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java @@ -8,6 +8,7 @@ import io.temporal.client.ActivityCompletionException; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.failure.ActivityFailure; import io.temporal.failure.CanceledFailure; import io.temporal.serviceclient.WorkflowServiceStubs; @@ -20,6 +21,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -231,13 +233,18 @@ private void sleep(int seconds) { */ public static void main(String[] args) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java index 6efb24b0a..5961b6833 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java @@ -4,12 +4,14 @@ import io.temporal.client.ActivityCompletionException; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.failure.ActivityFailure; import io.temporal.failure.CanceledFailure; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.*; +import java.io.IOException; import java.time.Duration; import java.util.concurrent.TimeUnit; @@ -153,12 +155,21 @@ private void sleep(int seconds) { public static void main(String[] args) { // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. */ - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloChild.java b/core/src/main/java/io/temporal/samples/hello/HelloChild.java index f631f5cbe..4c4c37276 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloChild.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloChild.java @@ -2,6 +2,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -10,6 +11,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; /** * Sample Temporal Workflow Definition that demonstrates the execution of a Child Workflow. Child @@ -105,13 +107,18 @@ public String composeGreeting(String greeting, String name) { */ public static void main(String[] args) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the worker factory. It is used to create workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCron.java b/core/src/main/java/io/temporal/samples/hello/HelloCron.java index 1d46d1c33..dafbfe11e 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloCron.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloCron.java @@ -7,12 +7,14 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowExecutionAlreadyStarted; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** @@ -108,13 +110,18 @@ public void greet(String greeting) { */ public static void main(String[] args) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java b/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java index 13d3d9041..a407e64d6 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java @@ -3,12 +3,14 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.common.WorkflowExecutionHistory; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** Sample Temporal Workflow Definition that shows how to use delayed start. */ @@ -50,13 +52,18 @@ public void start() { } public static void main(String[] args) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java index 8baaf2364..a40087894 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java @@ -8,11 +8,13 @@ import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.failure.ActivityFailure; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.*; +import java.io.IOException; import java.time.Duration; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -132,13 +134,22 @@ public String queryGreeting() { public static void main(String[] args) throws InterruptedException { // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); /* * Get a Workflow service client which can be used to start, Signal, and Query Workflow * Executions. */ - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java index f770f4263..f779bdfc3 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java @@ -7,6 +7,7 @@ import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.common.converter.EncodedValues; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -14,6 +15,7 @@ import io.temporal.workflow.DynamicSignalHandler; import io.temporal.workflow.DynamicWorkflow; import io.temporal.workflow.Workflow; +import java.io.IOException; import java.time.Duration; public class HelloDynamic { @@ -71,14 +73,18 @@ public Object execute(EncodedValues args) { */ public static void main(String[] arg) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow - * Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java b/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java index feb0d45f1..4e1a3b533 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java @@ -5,12 +5,14 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -110,13 +112,18 @@ public String composeGreeting(String greeting, String name) { */ public static void main(String[] args) { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloException.java b/core/src/main/java/io/temporal/samples/hello/HelloException.java index 8c1daaccb..6b0788043 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloException.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloException.java @@ -8,6 +8,7 @@ import io.temporal.client.WorkflowException; import io.temporal.client.WorkflowOptions; import io.temporal.common.RetryOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -153,13 +154,18 @@ public String composeGreeting(String greeting, String name) { */ public static void main(String[] args) { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java index 9436eab6b..c82a76e06 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java @@ -5,12 +5,14 @@ import io.temporal.activity.LocalActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** @@ -90,10 +92,19 @@ public String composeGreeting(String greeting, String name) { } public static void main(String[] args) { - // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // gRPC stubs wrapper that talks to the temporal service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java index ab3e7c789..21b716070 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java @@ -4,10 +4,12 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.*; +import java.io.IOException; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; @@ -116,13 +118,18 @@ public List getGreetings(List names) { */ public static void main(String[] args) { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java b/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java index 418244684..f26370f21 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java @@ -7,6 +7,7 @@ import io.temporal.client.WorkflowExecutionAlreadyStarted; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -14,6 +15,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.util.Random; @@ -183,13 +185,18 @@ public void greet(String greeting) { "CatchAndPrintStackTrace") // in this simple example advanced error logging is not required public static void main(String[] args) throws InterruptedException { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java index a6bb70f1f..71a2c3ffd 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java @@ -4,12 +4,14 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** @@ -150,13 +152,18 @@ public String composeGreeting(String name) { */ public static void main(String[] args) { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloQuery.java b/core/src/main/java/io/temporal/samples/hello/HelloQuery.java index 012ae1b97..e89f83f07 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloQuery.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloQuery.java @@ -2,6 +2,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -9,6 +10,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** Sample Temporal Workflow Definition that demonstrates how to Query a Workflow. */ @@ -78,13 +80,18 @@ public String queryGreeting() { */ public static void main(String[] args) throws InterruptedException { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSaga.java b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java index 5dfc0848b..4fb3bc6a1 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSaga.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java @@ -5,6 +5,7 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -14,6 +15,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; /** @@ -258,13 +260,18 @@ public void execute() { */ public static void main(String[] args) { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java b/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java index 7d3c5ef1a..698f4f83b 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java @@ -9,12 +9,14 @@ import io.temporal.client.WorkflowOptions; import io.temporal.client.schedules.*; import io.temporal.common.converter.GlobalDataConverter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.time.Instant; import java.util.Collections; @@ -130,13 +132,18 @@ public void greet(String greeting) { */ public static void main(String[] args) throws InterruptedException { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java index e2b1c0f9c..7115ebaa5 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java @@ -12,12 +12,14 @@ import io.temporal.client.WorkflowOptions; import io.temporal.common.converter.DataConverter; import io.temporal.common.converter.GlobalDataConverter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -113,13 +115,18 @@ public String composeGreeting(String greeting, String name) { */ public static void main(String[] args) { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java index e0c39bf91..f894dc343 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java @@ -4,6 +4,7 @@ import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -11,6 +12,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.security.SecureRandom; import java.time.Duration; import java.util.Random; @@ -159,14 +161,18 @@ public String sayGoodBye(String greeting) { */ public static void main(String[] args) { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow - * Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignal.java b/core/src/main/java/io/temporal/samples/hello/HelloSignal.java index cd5a488ab..e2e50fc85 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSignal.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSignal.java @@ -2,6 +2,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -9,6 +10,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -94,13 +96,18 @@ public void exit() { */ public static void main(String[] args) throws Exception { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java index 096516b10..f579388ae 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java @@ -6,11 +6,13 @@ import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkflowImplementationOptions; import io.temporal.workflow.*; +import java.io.IOException; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -147,8 +149,17 @@ public void setAge(int age) { } public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker(TASK_QUEUE); diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java index 26c22b2a2..ea2d29d2a 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java @@ -5,11 +5,13 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.failure.CanceledFailure; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.*; +import java.io.IOException; import java.time.Duration; import org.slf4j.Logger; @@ -116,8 +118,17 @@ public void processValue(String value) { } public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker(TASK_QUEUE); diff --git a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java index f0dfb76c4..8629dfd62 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java @@ -6,12 +6,14 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.common.SearchAttributeKey; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.time.OffsetDateTime; import java.time.ZoneOffset; @@ -149,13 +151,18 @@ public String composeGreeting(String greeting, List salutations, String */ public static void main(String[] args) { - // Define the workflow service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Define the workflow service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java b/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java index 329569738..6df8a8694 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java @@ -6,6 +6,7 @@ import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.client.WorkflowUpdateException; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.failure.ApplicationFailure; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; @@ -16,6 +17,7 @@ import io.temporal.workflow.Workflow; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; +import java.io.IOException; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -157,13 +159,18 @@ public void exit() { */ public static void main(String[] args) throws Exception { - // Get a Workflow service stub. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } - /* - * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions. - */ - WorkflowClient client = WorkflowClient.newInstance(service); + // Get a Workflow service stub. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); /* * Define the workflow factory. It is used to create workflow workers for a specific task queue. diff --git a/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java index 94570db98..ec6f8a5ba 100644 --- a/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java +++ b/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java @@ -5,6 +5,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.failure.ActivityFailure; import io.temporal.failure.CanceledFailure; import io.temporal.failure.ChildWorkflowFailure; @@ -12,6 +13,7 @@ import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.workflow.*; +import java.io.IOException; import java.time.Duration; /** Sample shows how to use workflow timer instead of WorkflowOptions->Run/ExecutionTimeout */ @@ -190,10 +192,19 @@ public String executeChild(String input) { } public static void main(String[] args) { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + // Create service stubs - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - // Crete workflow client - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + // Create workflow client + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // Create worker factory WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java index f36f3176c..03392674c 100644 --- a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java +++ b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java @@ -5,10 +5,12 @@ import io.temporal.client.WorkflowOptions; import io.temporal.common.converter.CodecDataConverter; import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.hello.HelloActivity; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import java.util.Collections; import software.amazon.cryptography.materialproviders.IKeyring; import software.amazon.cryptography.materialproviders.MaterialProviders; @@ -36,7 +38,16 @@ public static void main(String[] args) { CreateAwsKmsMultiKeyringInput.builder().generator(generatorKey).build(); final IKeyring kmsKeyring = materialProviders.CreateAwsKmsMultiKeyring(keyringInput); // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows WorkflowClient client = WorkflowClient.newInstance( diff --git a/core/src/main/java/io/temporal/samples/listworkflows/Starter.java b/core/src/main/java/io/temporal/samples/listworkflows/Starter.java index 1d9ef916c..ad7f62369 100644 --- a/core/src/main/java/io/temporal/samples/listworkflows/Starter.java +++ b/core/src/main/java/io/temporal/samples/listworkflows/Starter.java @@ -6,9 +6,11 @@ import io.temporal.api.workflowservice.v1.ListWorkflowExecutionsResponse; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -17,11 +19,23 @@ public class Starter { public static final String TASK_QUEUE = "customerTaskQueue"; - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); - private static final WorkerFactory factory = WorkerFactory.newInstance(client); + private static WorkflowServiceStubs service; + private static WorkflowClient client; + private static WorkerFactory factory; public static void main(String[] args) { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + factory = WorkerFactory.newInstance(client); + // create some fake customers List customers = new ArrayList<>(); customers.add(new Customer("c1", "John", "john@john.com", "new")); diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java index a213c3f81..ffe222899 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java @@ -9,9 +9,11 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.common.reporter.MicrometerClientStatsReporter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.metrics.workflow.MetricsWorkflow; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import java.io.IOException; public class MetricsStarter { public static void main(String[] args) { @@ -35,12 +37,22 @@ public static void main(String[] args) { // scrape endpoint. Runtime.getRuntime().addShutdownHook(new Thread(() -> scrapeEndpoint.stop(1))); - // Add metrics scope to workflow service stub options + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // Add metrics scope to workflow service stub options, preserving env config WorkflowServiceStubsOptions stubOptions = - WorkflowServiceStubsOptions.newBuilder().setMetricsScope(scope).build(); + WorkflowServiceStubsOptions.newBuilder(profile.toWorkflowServiceStubsOptions()) + .setMetricsScope(scope) + .build(); WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(stubOptions); - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkflowOptions workflowOptions = WorkflowOptions.newBuilder() diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java index 4b5f3173f..9f95107cf 100644 --- a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java +++ b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java @@ -8,12 +8,14 @@ import io.micrometer.prometheus.PrometheusMeterRegistry; import io.temporal.client.WorkflowClient; import io.temporal.common.reporter.MicrometerClientStatsReporter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.metrics.activities.MetricsActivitiesImpl; import io.temporal.samples.metrics.workflow.MetricsWorkflowImpl; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.serviceclient.WorkflowServiceStubsOptions; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class MetricsWorker { @@ -41,12 +43,22 @@ public static void main(String[] args) { // Stopping the worker will stop the http server that exposes the // scrape endpoint. Runtime.getRuntime().addShutdownHook(new Thread(() -> scrapeEndpoint.stop(1))); - // Add metrics scope to workflow service stub options + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // Add metrics scope to workflow service stub options, preserving env config WorkflowServiceStubsOptions stubOptions = - WorkflowServiceStubsOptions.newBuilder().setMetricsScope(scope).build(); + WorkflowServiceStubsOptions.newBuilder(profile.toWorkflowServiceStubsOptions()) + .setMetricsScope(scope) + .build(); WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(stubOptions); - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java index ecee1ad05..d67014f80 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java @@ -1,9 +1,11 @@ package io.temporal.samples.moneybatch; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class AccountActivityWorker { @@ -11,8 +13,17 @@ public class AccountActivityWorker { @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker(TASK_QUEUE); diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java index d9c5ef7cd..99529467d 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java @@ -1,16 +1,27 @@ package io.temporal.samples.moneybatch; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class AccountTransferWorker { @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker(AccountActivityWorker.TASK_QUEUE); diff --git a/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java b/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java index 8a63c02e3..31b2f507f 100644 --- a/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java +++ b/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java @@ -3,7 +3,9 @@ import io.temporal.client.BatchRequest; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; import java.util.Random; import java.util.UUID; @@ -16,8 +18,18 @@ public class TransferRequester { public static void main(String[] args) { String reference = UUID.randomUUID().toString(); int amountCents = (new Random().nextInt(5) + 1) * 25; - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient workflowClient = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient workflowClient = + WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); String from = "account1"; String to = "account2"; diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java index a2bbee418..a3113fe5d 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java @@ -1,9 +1,11 @@ package io.temporal.samples.moneytransfer; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class AccountActivityWorker { @@ -11,10 +13,19 @@ public class AccountActivityWorker { @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { - // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // gRPC stubs wrapper that talks to the temporal service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java index 6d237d8fa..97ab56ff9 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java @@ -3,19 +3,30 @@ import static io.temporal.samples.moneytransfer.AccountActivityWorker.TASK_QUEUE; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class AccountTransferWorker { @SuppressWarnings("CatchAndPrintStackTrace") public static void main(String[] args) { // Get worker to poll the common task queue. - // gRPC stubs wrapper that talks to the local docker instance of temporal service. - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + // gRPC stubs wrapper that talks to the temporal service. + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient client = WorkflowClient.newInstance(service); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // worker factory that can be used to create workers for specific task queues WorkerFactory factory = WorkerFactory.newInstance(client); diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java b/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java index b333b9341..6fda6598e 100644 --- a/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java +++ b/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java @@ -4,7 +4,9 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; import java.util.Random; import java.util.UUID; @@ -21,9 +23,19 @@ public static void main(String[] args) { reference = args[0]; amountCents = Integer.parseInt(args[1]); } - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // client that can be used to start and signal workflows - WorkflowClient workflowClient = WorkflowClient.newInstance(service); + WorkflowClient workflowClient = + WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // now we can start running instances of the saga - its state will be persisted WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build(); diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java b/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java index e1d97e621..f6ca6000d 100644 --- a/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java +++ b/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java @@ -4,16 +4,27 @@ import io.temporal.client.WorkflowNotFoundException; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import java.util.Collections; import java.util.List; public class Starter { public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker("packet-delivery-taskqueue"); diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java index 2e17f4cb0..e9e368a3b 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java @@ -7,9 +7,11 @@ import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowOptions; import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import java.net.URI; import java.nio.charset.Charset; import java.util.ArrayList; @@ -20,7 +22,16 @@ public class Starter { private static final String TASK_QUEUE = "CloudEventsConverterQueue"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // Add CloudEventsPayloadConverter // It has the same encoding type as JacksonJsonPayloadConverter diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java index dffdb41a1..4a5e121ef 100644 --- a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java +++ b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java @@ -9,16 +9,27 @@ import io.temporal.client.WorkflowOptions; import io.temporal.common.converter.DefaultDataConverter; import io.temporal.common.converter.JacksonJsonPayloadConverter; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class Starter { private static final String TASK_QUEUE = "CryptoConverterQueue"; private static final String encryptDecryptPassword = "encryptDecryptPassword"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); // Set crypto data converter in client options WorkflowClient client = diff --git a/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java b/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java index 7db5df86d..58062c176 100644 --- a/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java +++ b/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java @@ -5,20 +5,32 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.common.RetryOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkflowImplementationOptions; +import java.io.IOException; import java.time.Duration; public class Starter { public static final String TASK_QUEUE = "perActivityTaskQueue"; - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); - private static final WorkerFactory factory = WorkerFactory.newInstance(client); public static void main(String[] args) { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + WorkerFactory factory = WorkerFactory.newInstance(client); + // Create Worker Worker worker = factory.newWorker(TASK_QUEUE); // Register workflow impl and set the per-activity options diff --git a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java index 4a52cab2f..ed8fa477f 100644 --- a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java +++ b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java @@ -2,15 +2,31 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.polling.PollingWorkflow; import io.temporal.samples.polling.TestService; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class FrequentPollingStarter { - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); + private static WorkflowServiceStubs service; + private static WorkflowClient client; + + static { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + } + private static final String taskQueue = "pollingSampleQueue"; private static final String workflowId = "FrequentPollingSampleWorkflow"; diff --git a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java index 2a6cb7a85..f778ce287 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java @@ -2,15 +2,31 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.polling.PollingWorkflow; import io.temporal.samples.polling.TestService; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class InfrequentPollingStarter { - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); + private static WorkflowServiceStubs service; + private static WorkflowClient client; + + static { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + } + private static final String taskQueue = "pollingSampleQueue"; private static final String workflowId = "InfrequentPollingSampleWorkflow"; diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java index 81853ec71..93e3c9e6b 100644 --- a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java +++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java @@ -2,15 +2,31 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.polling.PollingWorkflow; import io.temporal.samples.polling.TestService; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class InfrequentPollingWithRetryAfterStarter { - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); + private static WorkflowServiceStubs service; + private static WorkflowClient client; + + static { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + } + private static final String taskQueue = "pollingSampleQueue"; private static final String workflowId = "InfrequentPollingWithRetryAfterWorkflow"; diff --git a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java index f2ef3eb1f..34c3e8a5a 100644 --- a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java +++ b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java @@ -2,15 +2,31 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.samples.polling.PollingWorkflow; import io.temporal.samples.polling.TestService; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class PeriodicPollingStarter { - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); + private static WorkflowServiceStubs service; + private static WorkflowClient client; + + static { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + } + private static final String taskQueue = "pollingSampleQueue"; private static final String workflowId = "PeriodicPollingSampleWorkflow"; diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java index cd3e546da..c948ba02e 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java @@ -3,7 +3,9 @@ import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; /** * Send signal requesting that an exception thrown from the activity is propagated to the workflow. @@ -11,8 +13,17 @@ public class FailureRequester { public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // Note that we use the listener interface that the interceptor registered dynamically, not the // workflow interface. diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java index 42fd358bd..55b9ebe17 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java @@ -2,10 +2,12 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerFactoryOptions; +import java.io.IOException; public class MyWorkflowWorker { @@ -14,8 +16,17 @@ public class MyWorkflowWorker { public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // Register interceptor with the factory. WorkerFactoryOptions factoryOptions = WorkerFactoryOptions.newBuilder() diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java index c54f8d0ab..08a7afcbb 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java @@ -3,13 +3,24 @@ import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; public class QueryRequester { public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // Note that we use the listener interface that the interceptor registered dynamically, not the // workflow interface. diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java index b0cf85ef8..a5469d80f 100644 --- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java +++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java @@ -3,13 +3,24 @@ import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; public class RetryRequester { public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // Note that we use the listener interface that the interceptor registered dynamically, not the // workflow interface. diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java index 1913a3e40..71ae380cb 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java @@ -7,7 +7,9 @@ import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.client.WorkflowUpdateStage; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -29,8 +31,17 @@ public static void main(String[] args) { + " "); System.exit(1); } - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); boolean shouldTestContinueAsNew = args.length > 0 ? Boolean.parseBoolean(args[0]) : false; ClusterManagerWorkflow cluster = client.newWorkflowStub( diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java index 2f063a663..a4fa8d69f 100644 --- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java +++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java @@ -1,9 +1,11 @@ package io.temporal.samples.safemessagepassing; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,8 +15,17 @@ public class ClusterManagerWorkflowWorker { static final String CLUSTER_MANAGER_WORKFLOW_ID = "ClusterManagerWorkflow"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); final Worker worker = factory.newWorker(TASK_QUEUE); worker.registerWorkflowImplementationTypes(ClusterManagerWorkflowImpl.class); diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java b/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java index cf5e9a9a7..91ed89325 100644 --- a/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java +++ b/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java @@ -3,15 +3,30 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; +import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; public class Starter { public static final String TASK_QUEUE = "SleepForDaysTaskQueue"; public static void main(String[] args) { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + // Start a workflow execution. SleepForDaysWorkflow workflow = - Worker.client.newWorkflowStub( + client.newWorkflowStub( SleepForDaysWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build()); diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java b/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java index 301326c27..b5abac1cb 100644 --- a/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java +++ b/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java @@ -1,16 +1,28 @@ package io.temporal.samples.sleepfordays; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.WorkerFactory; +import java.io.IOException; public class Worker { public static final String TASK_QUEUE = "SleepForDaysTaskQueue"; - public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - public static final WorkflowClient client = WorkflowClient.newInstance(service); - public static final WorkerFactory factory = WorkerFactory.newInstance(client); public static void main(String[] args) { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + WorkerFactory factory = WorkerFactory.newInstance(client); + io.temporal.worker.Worker worker = factory.newWorker(TASK_QUEUE); worker.registerWorkflowImplementationTypes(SleepForDaysImpl.class); worker.registerActivitiesImplementations(new SendEmailActivityImpl()); diff --git a/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java b/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java index 20f0d171d..e36a407c7 100644 --- a/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java +++ b/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java @@ -7,21 +7,33 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import java.util.concurrent.TimeUnit; public class Starter { public static final String TASK_QUEUE = "terminateQueue"; - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); - private static final WorkerFactory factory = WorkerFactory.newInstance(client); public static void main(String[] args) { + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + WorkerFactory factory = WorkerFactory.newInstance(client); + // Create Worker - createWorker(); + createWorker(factory); // Create Workflow options WorkflowOptions workflowOptions = @@ -44,13 +56,13 @@ public static void main(String[] args) { untyped.terminate("Sample reason"); // Check workflow status, should be WORKFLOW_EXECUTION_STATUS_TERMINATED - System.out.println("Status: " + getStatusAsString(execution)); + System.out.println("Status: " + getStatusAsString(execution, client, service)); System.exit(0); } /** This method creates a Worker from the factory. */ - private static void createWorker() { + private static void createWorker(WorkerFactory factory) { Worker worker = factory.newWorker(TASK_QUEUE); worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); @@ -78,7 +90,8 @@ private static void sleepSeconds(int seconds) { * @param execution workflow execution * @return Workflow status */ - private static String getStatusAsString(WorkflowExecution execution) { + private static String getStatusAsString( + WorkflowExecution execution, WorkflowClient client, WorkflowServiceStubs service) { DescribeWorkflowExecutionRequest describeWorkflowExecutionRequest = DescribeWorkflowExecutionRequest.newBuilder() .setNamespace(client.getOptions().getNamespace()) diff --git a/core/src/main/java/io/temporal/samples/tracing/Starter.java b/core/src/main/java/io/temporal/samples/tracing/Starter.java index ebb830c19..bb1eaaae3 100644 --- a/core/src/main/java/io/temporal/samples/tracing/Starter.java +++ b/core/src/main/java/io/temporal/samples/tracing/Starter.java @@ -4,12 +4,13 @@ import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.opentracing.OpenTracingClientInterceptor; import io.temporal.samples.tracing.workflow.TracingWorkflow; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; public class Starter { - public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); public static final String TASK_QUEUE_NAME = "tracingTaskQueue"; public static void main(String[] args) { @@ -18,9 +19,20 @@ public static void main(String[] args) { type = args[0]; } - // Set the OpenTracing client interceptor + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + + // Set the OpenTracing client interceptor, preserving env config WorkflowClientOptions clientOptions = - WorkflowClientOptions.newBuilder() + profile.toWorkflowClientOptions().toBuilder() .setInterceptors(new OpenTracingClientInterceptor(JaegerUtils.getJaegerOptions(type))) .build(); WorkflowClient client = WorkflowClient.newInstance(service, clientOptions); diff --git a/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java b/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java index 221c3efef..b726bcaae 100644 --- a/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java +++ b/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java @@ -1,6 +1,7 @@ package io.temporal.samples.tracing; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.opentracing.OpenTracingWorkerInterceptor; import io.temporal.samples.tracing.workflow.TracingActivitiesImpl; import io.temporal.samples.tracing.workflow.TracingChildWorkflowImpl; @@ -9,10 +10,9 @@ import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerFactoryOptions; +import java.io.IOException; public class TracingWorker { - private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - private static final WorkflowClient client = WorkflowClient.newInstance(service); public static final String TASK_QUEUE_NAME = "tracingTaskQueue"; public static void main(String[] args) { @@ -21,6 +21,18 @@ public static void main(String[] args) { type = args[0]; } + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); + // Set the OpenTracing client interceptor WorkerFactoryOptions factoryOptions = WorkerFactoryOptions.newBuilder() diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java index d1f38e1ab..0cd1bb14c 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java @@ -8,7 +8,9 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowExecutionAlreadyStarted; import io.temporal.client.WorkflowOptions; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,8 +19,17 @@ public class DynamicSleepWorkflowStarter { private static final Logger logger = LoggerFactory.getLogger(DynamicSleepWorkflowStarter.class); public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); DynamicSleepWorkflow workflow = client.newWorkflowStub( diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java index d0a4e712b..a7db34126 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java @@ -1,9 +1,11 @@ package io.temporal.samples.updatabletimer; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,8 +19,17 @@ public class DynamicSleepWorkflowWorker { static final String DYNAMIC_SLEEP_WORKFLOW_ID = "DynamicSleepWorkflow"; public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerFactory factory = WorkerFactory.newInstance(client); final Worker worker = factory.newWorker(TASK_QUEUE); worker.registerWorkflowImplementationTypes(DynamicSleepWorkflowImpl.class); diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java b/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java index 0a13ff071..3a8f935a2 100644 --- a/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java +++ b/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java @@ -3,7 +3,9 @@ import static io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker.DYNAMIC_SLEEP_WORKFLOW_ID; import io.temporal.client.WorkflowClient; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,8 +14,17 @@ public class WakeUpTimeUpdater { private static final Logger logger = LoggerFactory.getLogger(WakeUpTimeUpdater.class); public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // Create a stub that points to an existing workflow with the given ID DynamicSleepWorkflow workflow = diff --git a/core/src/main/java/io/temporal/samples/workerversioning/Starter.java b/core/src/main/java/io/temporal/samples/workerversioning/Starter.java index a48902557..b743cf821 100644 --- a/core/src/main/java/io/temporal/samples/workerversioning/Starter.java +++ b/core/src/main/java/io/temporal/samples/workerversioning/Starter.java @@ -7,7 +7,9 @@ import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; +import java.io.IOException; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,8 +21,17 @@ public class Starter { private static final Logger logger = LoggerFactory.getLogger(Starter.class); public static void main(String[] args) throws Exception { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); // Wait for v1 worker and set as current version logger.info( @@ -146,6 +157,7 @@ private static void waitForWorkerAndMakeCurrent( break; } } catch (Exception ignored) { + System.out.println(); } Thread.sleep(1000); } diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java index 6d90b82fd..42ff216e0 100644 --- a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java +++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java @@ -2,11 +2,13 @@ import io.temporal.client.WorkflowClient; import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerDeploymentOptions; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerOptions; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,8 +17,17 @@ public class WorkerV1 { private static final Logger logger = LoggerFactory.getLogger(WorkerV1.class); public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "1.0"); WorkerDeploymentOptions deploymentOptions = diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java index 5b1235460..76ec8e278 100644 --- a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java +++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java @@ -2,11 +2,13 @@ import io.temporal.client.WorkflowClient; import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerDeploymentOptions; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerOptions; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,8 +17,17 @@ public class WorkerV1_1 { private static final Logger logger = LoggerFactory.getLogger(WorkerV1_1.class); public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "1.1"); WorkerDeploymentOptions deploymentOptions = diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java index 57edd0ed3..2c436a2dd 100644 --- a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java +++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java @@ -2,11 +2,13 @@ import io.temporal.client.WorkflowClient; import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.envconfig.ClientConfigProfile; import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.worker.Worker; import io.temporal.worker.WorkerDeploymentOptions; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkerOptions; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,8 +17,17 @@ public class WorkerV2 { private static final Logger logger = LoggerFactory.getLogger(WorkerV2.class); public static void main(String[] args) { - WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); - WorkflowClient client = WorkflowClient.newInstance(service); + // Load configuration from environment and files + ClientConfigProfile profile; + try { + profile = ClientConfigProfile.load(); + } catch (IOException e) { + throw new RuntimeException("Failed to load client configuration", e); + } + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "2.0"); WorkerDeploymentOptions deploymentOptions = diff --git a/springboot/build.gradle b/springboot/build.gradle index 7120304e9..aa632df51 100644 --- a/springboot/build.gradle +++ b/springboot/build.gradle @@ -9,6 +9,9 @@ dependencies { // we set this as impl depends to use embedded kafka in samples not just tests implementation "org.springframework.kafka:spring-kafka-test" implementation "io.temporal:temporal-spring-boot-starter:$javaSDKVersion" + + // Environment configuration + implementation "io.temporal:temporal-envconfig:$javaSDKVersion" implementation "org.apache.camel.springboot:camel-spring-boot-starter:$camelVersion" implementation "org.apache.camel.springboot:camel-servlet-starter:$camelVersion" runtimeOnly "io.micrometer:micrometer-registry-prometheus" From 8c313585970165aa344ad8c14abcb2b70cb0c91b Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:12:16 -0800 Subject: [PATCH 233/240] docs: add snipsync lines to envconfig samples (#763) * docs: add snipsync lines to envconfig samples * docs: fix gradle format issues --- .../java/io/temporal/samples/envconfig/LoadFromFile.java | 6 ++++++ .../java/io/temporal/samples/envconfig/LoadProfile.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java b/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java index b6a9f7187..2a79c449b 100644 --- a/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java +++ b/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java @@ -1,5 +1,8 @@ package io.temporal.samples.envconfig; +/** + * @@@SNIPSTART java-env-config-profile + */ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.envconfig.ClientConfigProfile; @@ -77,3 +80,6 @@ public static void main(String[] args) { } } } +/** + * @@@SNIPEND + */ diff --git a/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java b/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java index 9d05b21f3..930912a74 100644 --- a/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java +++ b/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java @@ -1,5 +1,8 @@ package io.temporal.samples.envconfig; +/** + * @@@SNIPSTART java-env-config-profile-with-overrides + */ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.envconfig.ClientConfigProfile; @@ -85,3 +88,6 @@ public static void main(String[] args) { } } } +/** + * @@@SNIPEND + */ From dfef8ac2652ce67c87e3f55eab5d50a5d43d9f6f Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Mon, 12 Jan 2026 06:49:13 -0800 Subject: [PATCH 234/240] fix: use single-line comments for SNIP markers to avoid NotJavadoc warnings (#765) ErrorProne's NotJavadoc check flags `/**` block comments that aren't actual Javadoc. The SNIP markers are for documentation extraction, not Javadoc, so use `//` single-line comments instead. Co-authored-by: Maxim Fateev <1463622+mfateev@users.noreply.github.com> --- .../java/io/temporal/samples/envconfig/LoadFromFile.java | 8 ++------ .../java/io/temporal/samples/envconfig/LoadProfile.java | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java b/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java index 2a79c449b..cee9df5a5 100644 --- a/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java +++ b/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java @@ -1,8 +1,6 @@ package io.temporal.samples.envconfig; -/** - * @@@SNIPSTART java-env-config-profile - */ +// @@@SNIPSTART java-env-config-profile import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.envconfig.ClientConfigProfile; @@ -80,6 +78,4 @@ public static void main(String[] args) { } } } -/** - * @@@SNIPEND - */ +// @@@SNIPEND diff --git a/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java b/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java index 930912a74..20270e1f0 100644 --- a/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java +++ b/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java @@ -1,8 +1,6 @@ package io.temporal.samples.envconfig; -/** - * @@@SNIPSTART java-env-config-profile-with-overrides - */ +// @@@SNIPSTART java-env-config-profile-with-overrides import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.envconfig.ClientConfigProfile; @@ -88,6 +86,4 @@ public static void main(String[] args) { } } } -/** - * @@@SNIPEND - */ +// @@@SNIPEND From 6244cbe2ac899e39980d9979132ad8f0631ac97d Mon Sep 17 00:00:00 2001 From: Kent Gruber Date: Thu, 29 Jan 2026 13:00:57 -0500 Subject: [PATCH 235/240] Set explicit permissions for GitHub Actions workflows (#758) This change was made by an automated process to ensure all GitHub Actions workflows have explicitly defined permissions as per best practices. --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fc0b023a..54deeb6eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,7 @@ name: "Continuous Integration" on: [push, pull_request] +permissions: + contents: read jobs: validation: @@ -47,4 +49,4 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Run copyright and code format checks - run: ./gradlew --no-daemon spotlessCheck \ No newline at end of file + run: ./gradlew --no-daemon spotlessCheck From bf3515d0bfc70e348838c6ee3bf8a2e7023c40c6 Mon Sep 17 00:00:00 2001 From: tconley1428 Date: Thu, 29 Jan 2026 15:37:37 -0800 Subject: [PATCH 236/240] fix: propagate unit test exit codes in CI workflow (#768) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: propagate unit test exit codes in CI workflow Add --exit-code-from flag to docker compose command to ensure unit test failures properly fail the GitHub Actions job. πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Fix springboot test --------- Co-authored-by: Claude --- .github/workflows/ci.yml | 2 +- springboot/src/test/resources/application.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54deeb6eb..6eac7d64b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: Run unit tests run: | - docker compose -f ./docker/github/docker-compose.yaml up unit-test + docker compose -f ./docker/github/docker-compose.yaml up --exit-code-from unit-test unit-test code_format: name: Code format diff --git a/springboot/src/test/resources/application.yaml b/springboot/src/test/resources/application.yaml index b81a11934..017d28f90 100644 --- a/springboot/src/test/resources/application.yaml +++ b/springboot/src/test/resources/application.yaml @@ -15,6 +15,7 @@ spring: # enable test server for testing test-server: enabled: true + ignore-duplicate-definitions: true # data source config for tests that need it datasource: url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;DB_CLOSE_ON_EXIT=FALSE; From 385adc4816f01dc8429cf5032d6e54a2a1c44360 Mon Sep 17 00:00:00 2001 From: Evan Reynolds Date: Mon, 30 Mar 2026 14:38:45 -0700 Subject: [PATCH 237/240] Code samples for testing and mocking Nexus (#771) * Code samples for testing and mocking Nexus * Formatting changes from Spotless * Added two more classes that mock the Nexus Service itself * Renamed EchoHandler to EchoClient * Updating gradle wrapper validator * Changed NexusService name for clarity, modified two tests * Suppressing two false warnings that turned into build errors --- .github/workflows/ci.yml | 4 +- .../samples/nexus/caller/CallerStarter.java | 7 +- .../samples/nexus/caller/CallerWorker.java | 2 +- .../nexus/caller/EchoCallerWorkflowImpl.java | 8 +- .../nexus/caller/HelloCallerWorkflow.java | 4 +- .../nexus/caller/HelloCallerWorkflowImpl.java | 12 +- .../samples/nexus/handler/EchoClient.java | 7 ++ .../samples/nexus/handler/EchoClientImpl.java | 12 ++ .../samples/nexus/handler/HandlerWorker.java | 2 +- .../nexus/handler/HelloHandlerWorkflow.java | 4 +- .../handler/HelloHandlerWorkflowImpl.java | 14 +-- ...eImpl.java => SampleNexusServiceImpl.java} | 36 ++++-- ...usService.java => SampleNexusService.java} | 2 +- .../samples/nexus/service/description.md | 4 +- .../caller/CallerWorker.java | 4 +- .../caller/HelloCallerWorkflowImpl.java | 23 ++-- .../handler/HandlerWorker.java | 4 +- .../handler/HelloHandlerWorkflowImpl.java | 14 +-- .../samples/nexuscontextpropagation/README.MD | 2 +- .../caller/CallerStarter.java | 7 +- .../caller/CallerWorker.java | 2 +- .../caller/EchoCallerWorkflowImpl.java | 8 +- .../caller/HelloCallerWorkflowImpl.java | 12 +- .../handler/HandlerWorker.java | 2 +- .../handler/HelloHandlerWorkflowImpl.java | 14 +-- ...eImpl.java => SampleNexusServiceImpl.java} | 14 +-- .../caller/CallerStarter.java | 7 +- .../caller/CallerWorker.java | 2 +- .../caller/EchoCallerWorkflowImpl.java | 8 +- .../caller/HelloCallerWorkflow.java | 4 +- .../caller/HelloCallerWorkflowImpl.java | 12 +- .../handler/HandlerWorker.java | 2 +- .../handler/HelloHandlerWorkflow.java | 4 +- .../handler/HelloHandlerWorkflowImpl.java | 14 +-- ...eImpl.java => SampleNexusServiceImpl.java} | 12 +- .../caller/CallerWorkflowJunit5MockTest.java | 79 +++++++++++++ .../caller/CallerWorkflowJunit5Test.java | 58 ++++++++++ .../nexus/caller/CallerWorkflowMockTest.java | 92 +++++++++++++++ .../nexus/caller/CallerWorkflowTest.java | 53 ++++----- .../nexus/caller/NexusServiceJunit5Test.java | 105 ++++++++++++++++++ .../nexus/caller/NexusServiceMockTest.java | 104 +++++++++++++++++ 41 files changed, 629 insertions(+), 151 deletions(-) create mode 100644 core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java create mode 100644 core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java rename core/src/main/java/io/temporal/samples/nexus/handler/{NexusServiceImpl.java => SampleNexusServiceImpl.java} (62%) rename core/src/main/java/io/temporal/samples/nexus/service/{NexusService.java => SampleNexusService.java} (97%) rename core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/{NexusServiceImpl.java => SampleNexusServiceImpl.java} (84%) rename core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/{NexusServiceImpl.java => SampleNexusServiceImpl.java} (86%) create mode 100644 core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java create mode 100644 core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java create mode 100644 core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java create mode 100644 core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java create mode 100644 core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6eac7d64b..e3a085782 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,8 @@ jobs: name: "Gradle wrapper validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v3 + - uses: actions/checkout@v6 + - uses: gradle/actions/wrapper-validation@v5 unittest: name: Unit Tests diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java index be1cc788e..f207d64cf 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java @@ -4,7 +4,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,11 +26,12 @@ public static void main(String[] args) { logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); HelloCallerWorkflow helloWorkflow = client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); - execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN); logger.info( "Started HelloCallerWorkflow workflowId: {} runId: {}", execution.getWorkflowId(), execution.getRunId()); - logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + logger.info( + "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES)); } } diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java index 55186489e..5480917ba 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java @@ -21,7 +21,7 @@ public static void main(String[] args) { WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - "NexusService", + "SampleNexusService", NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) .build(), EchoCallerWorkflowImpl.class, diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java index 948008772..f76edbfe4 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java @@ -1,15 +1,15 @@ package io.temporal.samples.nexus.caller; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; import io.temporal.workflow.Workflow; import java.time.Duration; public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -19,6 +19,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { @Override public String echo(String message) { - return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage(); } } diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java index 173c0be8b..1f78e9c02 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java @@ -1,11 +1,11 @@ package io.temporal.samples.nexus.caller; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloCallerWorkflow { @WorkflowMethod - String hello(String message, NexusService.Language language); + String hello(String message, SampleNexusService.Language language); } diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java index f1612e359..6a6fe8dce 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java @@ -1,6 +1,6 @@ package io.temporal.samples.nexus.caller; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationHandle; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; @@ -8,9 +8,9 @@ import java.time.Duration; public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -19,10 +19,10 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { .build()); @Override - public String hello(String message, NexusService.Language language) { - NexusOperationHandle handle = + public String hello(String message, SampleNexusService.Language language) { + NexusOperationHandle handle = Workflow.startNexusOperation( - nexusService::hello, new NexusService.HelloInput(message, language)); + sampleNexusService::hello, new SampleNexusService.HelloInput(message, language)); // Optionally wait for the operation to be started. NexusOperationExecution will contain the // operation token in case this operation is asynchronous. handle.getExecution().get(); diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java new file mode 100644 index 000000000..74b6f6c69 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java @@ -0,0 +1,7 @@ +package io.temporal.samples.nexus.handler; + +import io.temporal.samples.nexus.service.SampleNexusService; + +public interface EchoClient { + SampleNexusService.EchoOutput echo(SampleNexusService.EchoInput input); +} diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java new file mode 100644 index 000000000..1c9a2e524 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java @@ -0,0 +1,12 @@ +package io.temporal.samples.nexus.handler; + +import io.temporal.samples.nexus.service.SampleNexusService; + +// Note that this is a class, not a Temporal worker. This is to demonstrate that Nexus services can +// simply call a class instead of a worker for fast operations that don't need retry handling. +public class EchoClientImpl implements EchoClient { + @Override + public SampleNexusService.EchoOutput echo(SampleNexusService.EchoInput input) { + return new SampleNexusService.EchoOutput(input.getMessage()); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java index 3d8afa3d7..656b18c65 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java @@ -15,7 +15,7 @@ public static void main(String[] args) { Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); - worker.registerNexusServiceImplementation(new NexusServiceImpl()); + worker.registerNexusServiceImplementation(new SampleNexusServiceImpl()); factory.start(); } diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java index 3cae13b31..2c85d0792 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java @@ -1,11 +1,11 @@ package io.temporal.samples.nexus.handler; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloHandlerWorkflow { @WorkflowMethod - NexusService.HelloOutput hello(NexusService.HelloInput input); + SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input); } diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java index c897a5181..b896ab523 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java @@ -1,22 +1,22 @@ package io.temporal.samples.nexus.handler; import io.temporal.failure.ApplicationFailure; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { @Override - public NexusService.HelloOutput hello(NexusService.HelloInput input) { + public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) { switch (input.getLanguage()) { case EN: - return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); case FR: - return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); case DE: - return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); case ES: - return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); case TR: - return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); } throw ApplicationFailure.newFailure( "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java similarity index 62% rename from core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java rename to core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java index 2344f27ec..42952b72b 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java @@ -6,27 +6,43 @@ import io.temporal.client.WorkflowOptions; import io.temporal.nexus.Nexus; import io.temporal.nexus.WorkflowRunOperation; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; // To create a service implementation, annotate the class with @ServiceImpl and provide the // interface that the service implements. The service implementation class should have methods that // return OperationHandler that correspond to the operations defined in the service interface. -@ServiceImpl(service = NexusService.class) -public class NexusServiceImpl { +@ServiceImpl(service = SampleNexusService.class) +public class SampleNexusServiceImpl { + private final EchoClient echoClient; + + // The injected EchoClient makes this class unit-testable. + // The no-arg constructor provides a default; the second allows tests to inject a mock. + // If you are not using the sync call or do not need to mock a handler, then you will not + // need this constructor pairing. + public SampleNexusServiceImpl() { + this(new EchoClientImpl()); + } + + public SampleNexusServiceImpl(EchoClient echoClient) { + this.echoClient = echoClient; + } + + // The Echo Nexus Service exemplifies making a synchronous call using OperationHandler.sync. + // In this case, it is calling the EchoClient class - not a workflow - and simply returning the + // result. @OperationImpl - public OperationHandler echo() { - // OperationHandler.sync is a meant for exposing simple RPC handlers. + public OperationHandler echo() { return OperationHandler.sync( // The method is for making arbitrary short calls to other services or databases, or // perform simple computations such as this one. Users can also access a workflow client by // calling // Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as // signaling, querying, or listing workflows. - (ctx, details, input) -> new NexusService.EchoOutput(input.getMessage())); + (ctx, details, input) -> echoClient.echo(input)); } @OperationImpl - public OperationHandler hello() { + public OperationHandler hello() { // Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest // way to expose a workflow as an operation. To expose a workflow with a different input // parameters then the operation or from an untyped stub, use the @@ -39,10 +55,8 @@ public OperationHandler hello .newWorkflowStub( HelloHandlerWorkflow.class, // Workflow IDs should typically be business meaningful IDs and are used to - // dedupe workflow starts. - // For this example, we're using the request ID allocated by Temporal when - // the - // caller workflow schedules + // dedupe workflow starts. For this example, we're using the request ID + // allocated by Temporal when the caller workflow schedules // the operation, this ID is guaranteed to be stable across retries of this // operation. // diff --git a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java b/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java similarity index 97% rename from core/src/main/java/io/temporal/samples/nexus/service/NexusService.java rename to core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java index ad65b1b33..180f9ec28 100644 --- a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java +++ b/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java @@ -6,7 +6,7 @@ import io.nexusrpc.Service; @Service -public interface NexusService { +public interface SampleNexusService { enum Language { EN, FR, diff --git a/core/src/main/java/io/temporal/samples/nexus/service/description.md b/core/src/main/java/io/temporal/samples/nexus/service/description.md index d79e151cd..b1cafb3a2 100644 --- a/core/src/main/java/io/temporal/samples/nexus/service/description.md +++ b/core/src/main/java/io/temporal/samples/nexus/service/description.md @@ -1,6 +1,6 @@ -## Service: [NexusService](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java) +## Service: [SampleNexusService](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java) - operation: `echo` - operation: `hello` -See https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java for Input / Output types. +See https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java for Input / Output types. diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java index cb05189cf..811cecde8 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java @@ -2,7 +2,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkflowImplementationOptions; @@ -22,7 +22,7 @@ public static void main(String[] args) { WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - NexusService.class.getSimpleName(), + SampleNexusService.class.getSimpleName(), NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) .build(), HelloCallerWorkflowImpl.class); diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java index 1bea801c8..6072906b4 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java @@ -1,10 +1,10 @@ package io.temporal.samples.nexuscancellation.caller; -import static io.temporal.samples.nexus.service.NexusService.Language.*; +import static io.temporal.samples.nexus.service.SampleNexusService.Language.*; import io.temporal.failure.CanceledFailure; import io.temporal.failure.NexusOperationFailure; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.*; import java.time.Duration; import java.util.ArrayList; @@ -13,11 +13,11 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { public static final Logger log = Workflow.getLogger(HelloCallerWorkflowImpl.class); - private static final NexusService.Language[] languages = - new NexusService.Language[] {EN, FR, DE, ES, TR}; - NexusService nexusService = + private static final SampleNexusService.Language[] languages = + new SampleNexusService.Language[] {EN, FR, DE, ES, TR}; + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -33,7 +33,7 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { @Override public String hello(String message) { - List> results = new ArrayList<>(languages.length); + List> results = new ArrayList<>(languages.length); /* * Create our CancellationScope. Within this scope we call the nexus operation asynchronously @@ -42,10 +42,11 @@ public String hello(String message) { CancellationScope scope = Workflow.newCancellationScope( () -> { - for (NexusService.Language language : languages) { + for (SampleNexusService.Language language : languages) { results.add( Async.function( - nexusService::hello, new NexusService.HelloInput(message, language))); + sampleNexusService::hello, + new SampleNexusService.HelloInput(message, language))); } }); @@ -56,7 +57,7 @@ public String hello(String message) { scope.run(); // We use "anyOf" here to wait for one of the nexus operation invocations to return - NexusService.HelloOutput result = Promise.anyOf(results).get(); + SampleNexusService.HelloOutput result = Promise.anyOf(results).get(); // Trigger cancellation of all uncompleted nexus operations invocations within the cancellation // scope @@ -67,7 +68,7 @@ public String hello(String message) { // Note: Once the workflow completes any pending cancellation requests are dropped by the // server. In general, it is a good practice to wait for all cancellation requests to be // processed before completing the workflow. - for (Promise promise : results) { + for (Promise promise : results) { try { promise.get(); } catch (NexusOperationFailure e) { diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java index 8b8949a70..f7d0f6940 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java @@ -1,7 +1,7 @@ package io.temporal.samples.nexuscancellation.handler; import io.temporal.client.WorkflowClient; -import io.temporal.samples.nexus.handler.NexusServiceImpl; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; import io.temporal.samples.nexus.options.ClientOptions; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -16,7 +16,7 @@ public static void main(String[] args) { Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); - worker.registerNexusServiceImplementation(new NexusServiceImpl()); + worker.registerNexusServiceImplementation(new SampleNexusServiceImpl()); factory.start(); } diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java index ca6510f60..de8b93557 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java @@ -3,7 +3,7 @@ import io.temporal.failure.ApplicationFailure; import io.temporal.failure.CanceledFailure; import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.Workflow; import java.time.Duration; import org.slf4j.Logger; @@ -12,21 +12,21 @@ public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { public static final Logger log = Workflow.getLogger(HelloHandlerWorkflowImpl.class); @Override - public NexusService.HelloOutput hello(NexusService.HelloInput input) { + public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) { // Sleep for a random duration to simulate some work try { Workflow.sleep(Duration.ofSeconds(Workflow.newRandom().nextInt(5))); switch (input.getLanguage()) { case EN: - return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); case FR: - return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); case DE: - return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); case ES: - return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); case TR: - return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); } throw ApplicationFailure.newFailure( "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD index 79453cc4d..54e2bc4f9 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD @@ -40,6 +40,6 @@ INFO i.t.s.n.caller.CallerStarter - Workflow result: Hello Nexus πŸ‘‹ And this on the handler side: ``` -INFO i.t.s.n.handler.NexusServiceImpl - Echo called from a workflow with ID : 7ac97cb9-b457-4052-af94-d82478c35c5e +INFO i.t.s.n.handler.SampleNexusServiceImpl - Echo called from a workflow with ID : 7ac97cb9-b457-4052-af94-d82478c35c5e INFO i.t.s.n.h.HelloHandlerWorkflowImpl - HelloHandlerWorkflow called from a workflow with ID : 9e0bc89c-5709-4742-b7c0-868464c2fccf ``` diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java index f0896221a..cfcc739de 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java @@ -7,7 +7,7 @@ import io.temporal.samples.nexus.caller.EchoCallerWorkflow; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.samples.nexuscontextpropagation.propagation.MDCContextPropagator; import java.util.Collections; import org.slf4j.Logger; @@ -35,11 +35,12 @@ public static void main(String[] args) { logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); HelloCallerWorkflow helloWorkflow = client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); - execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN); logger.info( "Started HelloCallerWorkflow workflowId: {} runId: {}", execution.getWorkflowId(), execution.getRunId()); - logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + logger.info( + "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES)); } } diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java index 13e568822..db3f1cfb9 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java @@ -28,7 +28,7 @@ public static void main(String[] args) { WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - "NexusService", + "SampleNexusService", NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) .build(), EchoCallerWorkflowImpl.class, diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java index 14e998629..3de27350d 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java @@ -1,7 +1,7 @@ package io.temporal.samples.nexuscontextpropagation.caller; import io.temporal.samples.nexus.caller.EchoCallerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; import io.temporal.workflow.Workflow; @@ -9,9 +9,9 @@ import org.slf4j.MDC; public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -22,6 +22,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { @Override public String echo(String message) { MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId()); - return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage(); } } diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java index fedefbc34..b817179a4 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java @@ -1,7 +1,7 @@ package io.temporal.samples.nexuscontextpropagation.caller; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationHandle; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; @@ -10,9 +10,9 @@ import org.slf4j.MDC; public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -21,11 +21,11 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { .build()); @Override - public String hello(String message, NexusService.Language language) { + public String hello(String message, SampleNexusService.Language language) { MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId()); - NexusOperationHandle handle = + NexusOperationHandle handle = Workflow.startNexusOperation( - nexusService::hello, new NexusService.HelloInput(message, language)); + sampleNexusService::hello, new SampleNexusService.HelloInput(message, language)); // Optionally wait for the operation to be started. NexusOperationExecution will contain the // operation token in case this operation is asynchronous. handle.getExecution().get(); diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java index c4f9ef54c..31b665a8a 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java @@ -29,7 +29,7 @@ public static void main(String[] args) { Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); - worker.registerNexusServiceImplementation(new NexusServiceImpl()); + worker.registerNexusServiceImplementation(new SampleNexusServiceImpl()); factory.start(); } diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java index a2db3cb0e..324ad34c1 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java @@ -2,7 +2,7 @@ import io.temporal.failure.ApplicationFailure; import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.Workflow; import org.slf4j.Logger; import org.slf4j.MDC; @@ -11,7 +11,7 @@ public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { public static final Logger log = Workflow.getLogger(HelloHandlerWorkflowImpl.class); @Override - public NexusService.HelloOutput hello(NexusService.HelloInput input) { + public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) { if (MDC.get("x-nexus-caller-workflow-id") != null) { log.info( "HelloHandlerWorkflow called from a workflow with ID : {}", @@ -19,15 +19,15 @@ public NexusService.HelloOutput hello(NexusService.HelloInput input) { } switch (input.getLanguage()) { case EN: - return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); case FR: - return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); case DE: - return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); case ES: - return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); case TR: - return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); } throw ApplicationFailure.newFailure( "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java similarity index 84% rename from core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java rename to core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java index 4977ff0c0..fc69e756b 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java @@ -7,7 +7,7 @@ import io.temporal.nexus.Nexus; import io.temporal.nexus.WorkflowRunOperation; import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; @@ -15,12 +15,12 @@ // To create a service implementation, annotate the class with @ServiceImpl and provide the // interface that the service implements. The service implementation class should have methods that // return OperationHandler that correspond to the operations defined in the service interface. -@ServiceImpl(service = NexusService.class) -public class NexusServiceImpl { - private static final Logger logger = LoggerFactory.getLogger(NexusServiceImpl.class); +@ServiceImpl(service = SampleNexusService.class) +public class SampleNexusServiceImpl { + private static final Logger logger = LoggerFactory.getLogger(SampleNexusServiceImpl.class); @OperationImpl - public OperationHandler echo() { + public OperationHandler echo() { // OperationHandler.sync is a meant for exposing simple RPC handlers. return OperationHandler.sync( // The method is for making arbitrary short calls to other services or databases, or @@ -33,12 +33,12 @@ public OperationHandler echo() logger.info( "Echo called from a workflow with ID : {}", MDC.get("x-nexus-caller-workflow-id")); } - return new NexusService.EchoOutput(input.getMessage()); + return new SampleNexusService.EchoOutput(input.getMessage()); }); } @OperationImpl - public OperationHandler hello() { + public OperationHandler hello() { // Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest // way to expose a workflow as an operation. To expose a workflow with a different input // parameters then the operation or from an untyped stub, use the diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java index beebdf406..4d3e7cff5 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java @@ -7,7 +7,7 @@ import io.temporal.samples.nexus.caller.EchoCallerWorkflow; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,11 +29,12 @@ public static void main(String[] args) { logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); HelloCallerWorkflow helloWorkflow = client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); - execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN); logger.info( "Started HelloCallerWorkflow workflowId: {} runId: {}", execution.getWorkflowId(), execution.getRunId()); - logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + logger.info( + "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES)); } } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java index 1db03a677..64272e6a2 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java @@ -21,7 +21,7 @@ public static void main(String[] args) { WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - "NexusService", + "SampleNexusService", NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) .build(), EchoCallerWorkflowImpl.class, diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java index ea9aaabb0..20d875ddb 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java @@ -1,16 +1,16 @@ package io.temporal.samples.nexusmultipleargs.caller; import io.temporal.samples.nexus.caller.EchoCallerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; import io.temporal.workflow.Workflow; import java.time.Duration; public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -20,6 +20,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { @Override public String echo(String message) { - return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage(); } } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java index aeb7a13db..03a8635ed 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java @@ -1,11 +1,11 @@ package io.temporal.samples.nexusmultipleargs.caller; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloCallerWorkflow { @WorkflowMethod - String hello(String message, NexusService.Language language); + String hello(String message, SampleNexusService.Language language); } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java index 94f4c3fc5..5d3c0824b 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java @@ -1,7 +1,7 @@ package io.temporal.samples.nexusmultipleargs.caller; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationHandle; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; @@ -9,9 +9,9 @@ import java.time.Duration; public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -20,10 +20,10 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { .build()); @Override - public String hello(String message, NexusService.Language language) { - NexusOperationHandle handle = + public String hello(String message, SampleNexusService.Language language) { + NexusOperationHandle handle = Workflow.startNexusOperation( - nexusService::hello, new NexusService.HelloInput(message, language)); + sampleNexusService::hello, new SampleNexusService.HelloInput(message, language)); // Optionally wait for the operation to be started. NexusOperationExecution will contain the // operation token in case this operation is asynchronous. handle.getExecution().get(); diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java index 0ec77889c..c3fd95e9f 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java @@ -15,7 +15,7 @@ public static void main(String[] args) { Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); - worker.registerNexusServiceImplementation(new NexusServiceImpl()); + worker.registerNexusServiceImplementation(new SampleNexusServiceImpl()); factory.start(); } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java index 0a443d468..d13906496 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java @@ -1,11 +1,11 @@ package io.temporal.samples.nexusmultipleargs.handler; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloHandlerWorkflow { @WorkflowMethod - NexusService.HelloOutput hello(String name, NexusService.Language language); + SampleNexusService.HelloOutput hello(String name, SampleNexusService.Language language); } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java index b802cee34..9d9cc3733 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java @@ -1,22 +1,22 @@ package io.temporal.samples.nexusmultipleargs.handler; import io.temporal.failure.ApplicationFailure; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { @Override - public NexusService.HelloOutput hello(String name, NexusService.Language language) { + public SampleNexusService.HelloOutput hello(String name, SampleNexusService.Language language) { switch (language) { case EN: - return new NexusService.HelloOutput("Hello " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hello " + name + " πŸ‘‹"); case FR: - return new NexusService.HelloOutput("Bonjour " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Bonjour " + name + " πŸ‘‹"); case DE: - return new NexusService.HelloOutput("Hallo " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hallo " + name + " πŸ‘‹"); case ES: - return new NexusService.HelloOutput("Β‘Hola! " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Β‘Hola! " + name + " πŸ‘‹"); case TR: - return new NexusService.HelloOutput("Merhaba " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Merhaba " + name + " πŸ‘‹"); } throw ApplicationFailure.newFailure( "Unsupported language: " + language, "UNSUPPORTED_LANGUAGE"); diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java similarity index 86% rename from core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java rename to core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java index 20d55fed8..b5d819267 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java @@ -7,15 +7,15 @@ import io.temporal.nexus.Nexus; import io.temporal.nexus.WorkflowHandle; import io.temporal.nexus.WorkflowRunOperation; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; // To create a service implementation, annotate the class with @ServiceImpl and provide the // interface that the service implements. The service implementation class should have methods that // return OperationHandler that correspond to the operations defined in the service interface. -@ServiceImpl(service = NexusService.class) -public class NexusServiceImpl { +@ServiceImpl(service = SampleNexusService.class) +public class SampleNexusServiceImpl { @OperationImpl - public OperationHandler echo() { + public OperationHandler echo() { // OperationHandler.sync is a meant for exposing simple RPC handlers. return OperationHandler.sync( // The method is for making arbitrary short calls to other services or databases, or @@ -23,11 +23,11 @@ public OperationHandler echo() // calling // Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as // signaling, querying, or listing workflows. - (ctx, details, input) -> new NexusService.EchoOutput(input.getMessage())); + (ctx, details, input) -> new SampleNexusService.EchoOutput(input.getMessage())); } @OperationImpl - public OperationHandler hello() { + public OperationHandler hello() { // If the operation input parameters are different from the workflow input parameters, // use the WorkflowRunOperation.fromWorkflowHandler constructor and the appropriate constructor // method on WorkflowHandle to map the Nexus input to the workflow parameters. diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java new file mode 100644 index 000000000..ca038ee0e --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java @@ -0,0 +1,79 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +import io.temporal.samples.nexus.handler.EchoClient; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +// This is an example of how to unit test Nexus services in JUnit5. The handlers are mocked, +// so that the caller classes interact with the mocks and not the handler classes themselves. + +public class CallerWorkflowJunit5MockTest { + + // Sync Nexus operations run inline in the handler thread β€” there is no backing workflow to + // register a factory for. To mock one, inject a mock dependency into the service implementation. + private static final EchoClient mockEchoClient = mock(EchoClient.class); + + @RegisterExtension + public static final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowExtension will, by default, automatically create a Nexus service + // endpoint and workflows registered as part of the TestWorkflowExtension will + // automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new SampleNexusServiceImpl(mockEchoClient)) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run, and the Echo Nexus caller service needs a worker. + // + // registerWorkflowImplementationTypes will take the classes given and create workers for + // them, enabling workflows to run. + .registerWorkflowImplementationTypes( + HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class) + .setDoNotStart(true) + .build(); + + @Test + public void testHelloWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) { + // Workflows started by a Nexus service can be mocked just like any other workflow + worker.registerWorkflowImplementationFactory( + HelloHandlerWorkflow.class, + () -> { + HelloHandlerWorkflow mockHandler = mock(HelloHandlerWorkflow.class); + when(mockHandler.hello(any())) + .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World πŸ‘‹")); + return mockHandler; + }); + testEnv.start(); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.hello("World", SampleNexusService.Language.EN); + assertEquals("Hello Mock World πŸ‘‹", greeting); + + testEnv.shutdown(); + } + + @Test + public void testEchoWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) { + // Sync Nexus operations run inline in the handler thread β€” there is no backing workflow to + // register a factory for. Instead, stub the injected EchoClient dependency directly. + when(mockEchoClient.echo(any())).thenReturn(new SampleNexusService.EchoOutput("mocked echo")); + testEnv.start(); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.echo("Hello"); + assertEquals("mocked echo", greeting); + + testEnv.shutdown(); + } +} diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java new file mode 100644 index 000000000..3da730c14 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java @@ -0,0 +1,58 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.temporal.samples.nexus.handler.HelloHandlerWorkflowImpl; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +// This is an example of how to unit test Nexus services in JUnit5. The handlers are not mocked, +// but are actually called by the testing framework by the caller classes. + +public class CallerWorkflowJunit5Test { + + @RegisterExtension + public static final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowExtension will, by default, automatically create a Nexus service + // endpoint and workflows registered as part of the TestWorkflowExtension will + // automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new SampleNexusServiceImpl()) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run, and the Echo Nexus caller service needs a worker. + // + // registerWorkflowImplementationTypes will take the classes given and create workers for + // them, enabling workflows to run. + .registerWorkflowImplementationTypes( + HelloCallerWorkflowImpl.class, + HelloHandlerWorkflowImpl.class, + EchoCallerWorkflowImpl.class) + // The workflow will start before each test, and will shut down after each test. + // See CallerWorkflowTest for an example of how to control this differently if needed. + .build(); + + // The TestWorkflowExtension extension in the Temporal testing library creates the + // arguments to the test cases and initializes them from the extension setup call above. + @Test + public void testHelloWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) { + // Execute a workflow waiting for it to complete. + String greeting = workflow.hello("World", SampleNexusService.Language.EN); + assertEquals("Hello World πŸ‘‹", greeting); + } + + @Test + public void testEchoWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) { + // Execute a workflow waiting for it to complete. + String greeting = workflow.echo("Hello"); + assertEquals("Hello", greeting); + } +} diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java new file mode 100644 index 000000000..c899713a2 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java @@ -0,0 +1,92 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.nexus.handler.EchoClient; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Rule; +import org.junit.Test; + +// This is an example of how to unit test Nexus services in JUnit4. The handlers are mocked, +// so that the caller classes interact with the mocks and not the handler classes themselves. + +public class CallerWorkflowMockTest { + + // Inject a mock EchoClient so sync Nexus operations can be stubbed per test. + // JUnit 4 creates a new test class instance per test method, so this mock is fresh each time. + private final EchoClient mockEchoClient = mock(EchoClient.class); + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowRule will, by default, automatically create a Nexus service endpoint + // and workflows registered as part of the TestWorkflowRule + // will automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new SampleNexusServiceImpl(mockEchoClient)) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run. + // setWorkflowTypes will take the classes given and create workers for them, enabling + // workflows to run. This creates caller workflows, the handler workflows + // will be mocked in the test methods. + .setWorkflowTypes(HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class) + // Disable automatic worker startup as we are going to register some workflows manually + // per test + .setDoNotStart(true) + .build(); + + @Test + public void testHelloWorkflow() { + testWorkflowRule + .getWorker() + // Workflows started by a Nexus service can be mocked just like any other workflow + .registerWorkflowImplementationFactory( + HelloHandlerWorkflow.class, + () -> { + HelloHandlerWorkflow wf = mock(HelloHandlerWorkflow.class); + when(wf.hello(any())) + .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World πŸ‘‹")); + return wf; + }); + testWorkflowRule.getTestEnvironment().start(); + + // Now create the caller workflow + HelloCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + String greeting = workflow.hello("World", SampleNexusService.Language.EN); + assertEquals("Hello Mock World πŸ‘‹", greeting); + + testWorkflowRule.getTestEnvironment().shutdown(); + } + + @Test + public void testEchoWorkflow() { + // Sync Nexus operations run inline in the handler thread β€” there is no backing workflow to + // register a factory for. Instead, stub the injected EchoCient dependency directly. + when(mockEchoClient.echo(any())).thenReturn(new SampleNexusService.EchoOutput("mocked echo")); + testWorkflowRule.getTestEnvironment().start(); + + EchoCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + EchoCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + String greeting = workflow.echo("Hello"); + assertEquals("mocked echo", greeting); + + testWorkflowRule.getTestEnvironment().shutdown(); + } +} diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java index 2d3a6e42a..682995e61 100644 --- a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java @@ -1,14 +1,11 @@ package io.temporal.samples.nexus.caller; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import io.temporal.client.WorkflowOptions; -import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; -import io.temporal.samples.nexus.handler.NexusServiceImpl; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflowImpl; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.testing.TestWorkflowRule; import io.temporal.worker.WorkflowImplementationOptions; import io.temporal.workflow.NexusServiceOptions; @@ -16,16 +13,27 @@ import org.junit.Rule; import org.junit.Test; +// This is an example of how to unit test Nexus services in JUnit4. The handlers are not mocked, +// but are actually called by the testing framework by the caller classes. + public class CallerWorkflowTest { @Rule public TestWorkflowRule testWorkflowRule = TestWorkflowRule.newBuilder() - // If a Nexus service is registered as part of the test, the TestWorkflowRule will ,by - // default, automatically create a Nexus service endpoint and workflows registered as part - // of the TestWorkflowRule will automatically inherit the endpoint if none is set. - .setNexusServiceImplementation(new NexusServiceImpl()) - .setWorkflowTypes(HelloCallerWorkflowImpl.class) + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowRule will, by default, automatically create a Nexus service endpoint + // and workflows registered as part of the TestWorkflowRule + // will automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new SampleNexusServiceImpl()) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run. + // setWorkflowTypes will take the classes given and create workers for them, enabling + // workflows to run. This is not adding an EchoCallerWorkflow though - + // see the testEchoWorkflow test method below for an example of an alternate way + // to supply a worker that gives you more flexibility if needed. + .setWorkflowTypes(HelloCallerWorkflowImpl.class, HelloHandlerWorkflowImpl.class) // Disable automatic worker startup as we are going to register some workflows manually // per test .setDoNotStart(true) @@ -33,16 +41,6 @@ public class CallerWorkflowTest { @Test public void testHelloWorkflow() { - testWorkflowRule - .getWorker() - // Workflows started by a Nexus service can be mocked just like any other workflow - .registerWorkflowImplementationFactory( - HelloHandlerWorkflow.class, - () -> { - HelloHandlerWorkflow wf = mock(HelloHandlerWorkflow.class); - when(wf.hello(any())).thenReturn(new NexusService.HelloOutput("Hello World πŸ‘‹")); - return wf; - }); testWorkflowRule.getTestEnvironment().start(); HelloCallerWorkflow workflow = @@ -51,7 +49,7 @@ public void testHelloWorkflow() { .newWorkflowStub( HelloCallerWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); - String greeting = workflow.hello("World", NexusService.Language.EN); + String greeting = workflow.hello("World", SampleNexusService.Language.EN); assertEquals("Hello World πŸ‘‹", greeting); testWorkflowRule.getTestEnvironment().shutdown(); @@ -61,15 +59,20 @@ public void testHelloWorkflow() { public void testEchoWorkflow() { // If Workflows are registered later than the endpoint can be set manually // either by setting the endpoint in the NexusServiceOptions in the Workflow implementation or - // by setting the NexusServiceOptions on the WorkflowImplementationOptions when registering the - // Workflow. + // by setting the NexusServiceOptions on the WorkflowImplementationOptions when registering + // the Workflow. To demonstrate, this is creating the Nexus service for Echo, + // and registering a EchoCallerWorkflowImpl worker. + // + // It is much simpler to use the setWorkflowTypes in the rule definition above - and as + // this isn't easily do-able in JUnit5 (the nexus endpoint isn't exposed) should be + // used with caution. testWorkflowRule .getWorker() .registerWorkflowImplementationTypes( WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - "NexusService", + "SampleNexusService", NexusServiceOptions.newBuilder() .setEndpoint(testWorkflowRule.getNexusEndpoint().getSpec().getName()) .build())) diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java new file mode 100644 index 000000000..c5fd578c0 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java @@ -0,0 +1,105 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import io.nexusrpc.handler.OperationHandler; +import io.nexusrpc.handler.OperationImpl; +import io.nexusrpc.handler.ServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +// This unit test example shows how to mock the Nexus service itself in JUnit4. +// This is the path to take when you don't have access to the service implementation so +// cannot mock it. Since the SampleNexusService itself is mocked, +// no handlers need to be set up or mocked. +public class NexusServiceJunit5Test { + + private final SampleNexusService mockNexusService = mock(SampleNexusService.class); + + /** + * A test-only Nexus service implementation that delegates to the Mockito mock defined above. Both + * operations are implemented as synchronous handlers that forward calls to the mock, allowing + * full control over return values and verification of inputs. + */ + @ServiceImpl(service = SampleNexusService.class) + public class TestNexusServiceImpl { + @OperationImpl + @SuppressWarnings("DirectInvocationOnMock") + public OperationHandler echo() { + return OperationHandler.sync((ctx, details, input) -> mockNexusService.echo(input)); + } + + @OperationImpl + @SuppressWarnings("DirectInvocationOnMock") + public OperationHandler hello() { + return OperationHandler.sync((ctx, details, input) -> mockNexusService.hello(input)); + } + } + + // Using OperationHandler.sync for both operations bypasses the need for a backing workflow, + // returning results inline just like a synchronous call. + // + // Note that the Mocks need to be done before the extension + // is defined, as creating the rule will fail if either call is still null. + + @RegisterExtension + public final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowExtension will, by default, automatically create a Nexus service + // endpoint and workflows registered as part of the TestWorkflowExtension will + // automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new TestNexusServiceImpl()) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run, and the Echo Nexus caller service needs a worker. + // + // registerWorkflowImplementationTypes will take the classes given and create workers for + // them, enabling workflows to run. + // Since both operations are mocked with OperationHandler.sync, no backing workflow is + // needed for hello β€” only the caller workflow types need to be registered. + .registerWorkflowImplementationTypes( + HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class) + // The workflow will start before each test, and will shut down after each test. + // See CallerWorkflowTest for an example of how to control this differently if needed. + .build(); + + // The TestWorkflowExtension extension in the Temporal testing library creates the + // arguments to the test cases and initializes them from the extension setup call above. + @Test + public void testHelloWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) { + + // Set the mock value to return + when(mockNexusService.hello(any())) + .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World πŸ‘‹")); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.hello("World", SampleNexusService.Language.EN); + assertEquals("Hello Mock World πŸ‘‹", greeting); + } + + @Test + public void testEchoWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) { + when(mockNexusService.echo(any())) + .thenReturn(new SampleNexusService.EchoOutput("echo response")); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.echo("echo input"); + assertEquals("echo response", greeting); + + // Verify the echo operation was called exactly once and no other operations were invoked + verify(mockNexusService, times(1)).echo(any()); + // Verify the Nexus service was called with the correct input + verify(mockNexusService).echo(argThat(input -> "echo input".equals(input.getMessage()))); + + verifyNoMoreInteractions(mockNexusService); + } +} diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java new file mode 100644 index 000000000..c2264ec65 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java @@ -0,0 +1,104 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import io.nexusrpc.handler.OperationHandler; +import io.nexusrpc.handler.OperationImpl; +import io.nexusrpc.handler.ServiceImpl; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Rule; +import org.junit.Test; + +// This unit test example shows how to mock the Nexus service itself in JUnit4. +// This is the path to take when you don't have access to the service implementation so +// cannot mock it. Since the SampleNexusService itself is mocked, +// no handlers need to be set up or mocked. +public class NexusServiceMockTest { + + private final SampleNexusService mockNexusService = mock(SampleNexusService.class); + + /** + * A test-only Nexus service implementation that delegates to the Mockito mock defined above. Both + * operations are implemented as synchronous handlers that forward calls to the mock, allowing + * full control over return values and verification of inputs. + */ + @ServiceImpl(service = SampleNexusService.class) + public class TestNexusServiceImpl { + @OperationImpl + @SuppressWarnings("DirectInvocationOnMock") + public OperationHandler echo() { + return OperationHandler.sync((ctx, details, input) -> mockNexusService.echo(input)); + } + + @OperationImpl + @SuppressWarnings("DirectInvocationOnMock") + public OperationHandler hello() { + return OperationHandler.sync((ctx, details, input) -> mockNexusService.hello(input)); + } + } + + // Using OperationHandler.sync for both operations bypasses the need for a backing workflow, + // returning results inline just like a synchronous call. + // + // Note that the Mocks need to be done before the rule + // is defined, as creating the rule will fail if either call is still null. + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setNexusServiceImplementation(new TestNexusServiceImpl()) + .setWorkflowTypes(EchoCallerWorkflowImpl.class, HelloCallerWorkflowImpl.class) + .build(); + + @Test + public void testHelloCallerWithMockedService() { + when(mockNexusService.hello(any())) + .thenReturn(new SampleNexusService.HelloOutput("Bonjour World")); + + HelloCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + String result = workflow.hello("World", SampleNexusService.Language.FR); + assertEquals("Bonjour World", result); + + // Verify the Nexus service was called with the correct name and language + verify(mockNexusService) + .hello( + argThat( + input -> + "World".equals(input.getName()) + && SampleNexusService.Language.FR == input.getLanguage())); + } + + @Test + public void testEchoCallerWithMockedService() { + when(mockNexusService.echo(any())) + .thenReturn(new SampleNexusService.EchoOutput("echo response")); + + EchoCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + EchoCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + String echoOutput = workflow.echo("echo input"); + + assertEquals("echo response", echoOutput); + + // Verify the echo operation was called exactly once and no other operations were invoked + verify(mockNexusService, times(1)).echo(any()); + // Verify the Nexus service was called with the correct input + verify(mockNexusService).echo(argThat(input -> "echo input".equals(input.getMessage()))); + + verifyNoMoreInteractions(mockNexusService); + } +} From d6f0a08055a6aee674724998da0885393322cb11 Mon Sep 17 00:00:00 2001 From: Evan Reynolds Date: Thu, 2 Apr 2026 11:29:51 -0700 Subject: [PATCH 238/240] Adding snips for documentation pages (#772) --- .../samples/nexus/caller/CallerWorkflowJunit5MockTest.java | 3 +++ .../temporal/samples/nexus/caller/CallerWorkflowMockTest.java | 3 +++ .../temporal/samples/nexus/caller/NexusServiceJunit5Test.java | 4 ++++ .../temporal/samples/nexus/caller/NexusServiceMockTest.java | 4 ++++ 4 files changed, 14 insertions(+) diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java index ca038ee0e..2ba042308 100644 --- a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java @@ -16,6 +16,7 @@ // This is an example of how to unit test Nexus services in JUnit5. The handlers are mocked, // so that the caller classes interact with the mocks and not the handler classes themselves. +// @@@SNIPSTART java-nexus-sample-junit5-mock public class CallerWorkflowJunit5MockTest { // Sync Nexus operations run inline in the handler thread β€” there is no backing workflow to @@ -77,3 +78,5 @@ public void testEchoWorkflow( testEnv.shutdown(); } } + +// @@@SNIPEND diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java index c899713a2..d6b793ffe 100644 --- a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java @@ -17,6 +17,7 @@ // This is an example of how to unit test Nexus services in JUnit4. The handlers are mocked, // so that the caller classes interact with the mocks and not the handler classes themselves. +// @@@SNIPSTART java-nexus-sample-junit4-mock public class CallerWorkflowMockTest { // Inject a mock EchoClient so sync Nexus operations can be stubbed per test. @@ -90,3 +91,5 @@ public void testEchoWorkflow() { testWorkflowRule.getTestEnvironment().shutdown(); } } + +// @@@SNIPEND diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java index c5fd578c0..fe8a8b8c9 100644 --- a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java +++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java @@ -18,6 +18,8 @@ // This is the path to take when you don't have access to the service implementation so // cannot mock it. Since the SampleNexusService itself is mocked, // no handlers need to be set up or mocked. + +// @@@SNIPSTART java-nexus-service-sample-junit4-mock public class NexusServiceJunit5Test { private final SampleNexusService mockNexusService = mock(SampleNexusService.class); @@ -103,3 +105,5 @@ public void testEchoWorkflow( verifyNoMoreInteractions(mockNexusService); } } + +// @@@SNIPEND diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java index c2264ec65..8dafc6388 100644 --- a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java +++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java @@ -17,6 +17,8 @@ // This is the path to take when you don't have access to the service implementation so // cannot mock it. Since the SampleNexusService itself is mocked, // no handlers need to be set up or mocked. + +// @@@SNIPSTART java-nexus-service-sample-junit4-mock public class NexusServiceMockTest { private final SampleNexusService mockNexusService = mock(SampleNexusService.class); @@ -102,3 +104,5 @@ public void testEchoCallerWithMockedService() { verifyNoMoreInteractions(mockNexusService); } } + +// @@@SNIPEND From d34d613a012e2a07586071e6d9aff69d433d45b9 Mon Sep 17 00:00:00 2001 From: Evan Reynolds Date: Thu, 2 Apr 2026 15:40:35 -0700 Subject: [PATCH 239/240] Updated snipstart tag (#774) --- .../temporal/samples/nexus/caller/NexusServiceJunit5Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java index fe8a8b8c9..0b03b2d64 100644 --- a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java +++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java @@ -19,7 +19,7 @@ // cannot mock it. Since the SampleNexusService itself is mocked, // no handlers need to be set up or mocked. -// @@@SNIPSTART java-nexus-service-sample-junit4-mock +// @@@SNIPSTART java-nexus-service-sample-junit5-mock public class NexusServiceJunit5Test { private final SampleNexusService mockNexusService = mock(SampleNexusService.class); From 4c1af4776630a02b2c6ec253d5617e6a266102e1 Mon Sep 17 00:00:00 2001 From: James Watkins-Harvey Date: Mon, 6 Apr 2026 23:28:29 -0400 Subject: [PATCH 240/240] Update Java SDK version to 1.34.0 (#773) --- build.gradle | 2 +- core/build.gradle | 1 + core/src/main/java/io/temporal/samples/ssl/Starter.java | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index abb6487ba..0cafde690 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ subprojects { ext { otelVersion = '1.30.1' otelVersionAlpha = "${otelVersion}-alpha" - javaSDKVersion = '1.32.1' + javaSDKVersion = '1.34.0' camelVersion = '3.22.1' jarVersion = '1.0.0' } diff --git a/core/build.gradle b/core/build.gradle index 62fbfa8e9..c5157db3d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -8,6 +8,7 @@ dependencies { implementation "io.temporal:temporal-envconfig:$javaSDKVersion" // Needed for SDK related functionality + implementation "io.grpc:grpc-util" implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.2")) implementation "com.fasterxml.jackson.core:jackson-databind" implementation "com.fasterxml.jackson.core:jackson-core" diff --git a/core/src/main/java/io/temporal/samples/ssl/Starter.java b/core/src/main/java/io/temporal/samples/ssl/Starter.java index c69101473..25b9df6ba 100644 --- a/core/src/main/java/io/temporal/samples/ssl/Starter.java +++ b/core/src/main/java/io/temporal/samples/ssl/Starter.java @@ -50,9 +50,9 @@ public static void main(String[] args) throws Exception { if (refreshPeriod > 0) { AdvancedTlsX509KeyManager clientKeyManager = new AdvancedTlsX509KeyManager(); // Reload credentials every minute - clientKeyManager.updateIdentityCredentialsFromFile( - clientKeyFile, + clientKeyManager.updateIdentityCredentials( clientCertFile, + clientKeyFile, refreshPeriod, TimeUnit.MINUTES, Executors.newScheduledThreadPool(1));