diff --git a/saas-modules/pom.xml b/saas-modules/pom.xml index 22213de48b90..91c04bb34770 100644 --- a/saas-modules/pom.xml +++ b/saas-modules/pom.xml @@ -25,6 +25,7 @@ twilio twilio-whatsapp twitter4j + temporal diff --git a/saas-modules/temporal/pom.xml b/saas-modules/temporal/pom.xml new file mode 100644 index 000000000000..f2ae5d41dbfd --- /dev/null +++ b/saas-modules/temporal/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + temporal + 1.0 + temporal + Temporal Workflow Engine Tutorial + + + com.baeldung + saas-modules + 1.0.0-SNAPSHOT + + + + + io.temporal + temporal-sdk + ${temporal.version} + + + + io.temporal + temporal-testing + ${temporal.version} + test + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + + + 1.31.0 + + + diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/worker/TemporalWorkerRegistrar.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/worker/TemporalWorkerRegistrar.java new file mode 100644 index 000000000000..5142fdfcd10e --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/worker/TemporalWorkerRegistrar.java @@ -0,0 +1,10 @@ +package com.baeldung.temporal.worker; + +import io.temporal.worker.Worker; + +/** + * Interface for registering Workflows and Activities to a Temporal Worker. + */ +public interface TemporalWorkerRegistrar { + void register(Worker worker); +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflow.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflow.java new file mode 100644 index 000000000000..8d915b8c396b --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflow.java @@ -0,0 +1,10 @@ +package com.baeldung.temporal.workflows.hello; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloWorkflow { + @WorkflowMethod + String hello(String person); +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowApplication.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowApplication.java new file mode 100644 index 000000000000..e0dd1db6dadd --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowApplication.java @@ -0,0 +1,29 @@ +package com.baeldung.temporal.workflows.hello; + +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 HelloWorkflowApplication { + + private static final String QUEUE_NAME = "say-hello-queue"; + private static final Logger log = LoggerFactory.getLogger(HelloWorkflowApplication.class); + + public static void main(String[] args) { + + log.info("Creating worker..."); + var service = WorkflowServiceStubs.newLocalServiceStubs(); + var client = WorkflowClient.newInstance(service); + var factory = WorkerFactory.newInstance(client); + var worker = factory.newWorker(QUEUE_NAME); + + log.info("Registering workflows and activities..."); + HelloWorkflowRegistrar.newInstance().register(worker); + + log.info("Starting worker..."); + factory.start(); + } +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowImpl.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowImpl.java new file mode 100644 index 000000000000..fdb718026185 --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowImpl.java @@ -0,0 +1,22 @@ +package com.baeldung.temporal.workflows.hello; + +import com.baeldung.temporal.workflows.hello.activities.SayHelloActivity; +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Workflow; + +import java.time.Duration; + +public class HelloWorkflowImpl implements HelloWorkflow { + + private final SayHelloActivity activity = Workflow.newActivityStub( + SayHelloActivity.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(10)) + .build() + ); + + @Override + public String hello(String person) { + return activity.sayHello(person); + } +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowRegistrar.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowRegistrar.java new file mode 100644 index 000000000000..ebc61d4992ce --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/HelloWorkflowRegistrar.java @@ -0,0 +1,20 @@ +package com.baeldung.temporal.workflows.hello; + +import com.baeldung.temporal.worker.TemporalWorkerRegistrar; +import com.baeldung.temporal.workflows.hello.activities.SayHelloActivityImpl; +import io.temporal.worker.Worker; + +public class HelloWorkflowRegistrar implements TemporalWorkerRegistrar { + + private HelloWorkflowRegistrar() {} + + @Override + public void register(Worker worker) { + worker.registerWorkflowImplementationTypes(HelloWorkflowImpl.class); + worker.registerActivitiesImplementations(new SayHelloActivityImpl()); + } + + public static HelloWorkflowRegistrar newInstance() { + return new HelloWorkflowRegistrar(); + } +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/activities/SayHelloActivity.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/activities/SayHelloActivity.java new file mode 100644 index 000000000000..57a22e0f7591 --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/activities/SayHelloActivity.java @@ -0,0 +1,10 @@ +package com.baeldung.temporal.workflows.hello.activities; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; + +@ActivityInterface +public interface SayHelloActivity { + @ActivityMethod + String sayHello(String person); +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/activities/SayHelloActivityImpl.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/activities/SayHelloActivityImpl.java new file mode 100644 index 000000000000..70f8cb8427cb --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hello/activities/SayHelloActivityImpl.java @@ -0,0 +1,14 @@ +package com.baeldung.temporal.workflows.hello.activities; + +import io.temporal.activity.Activity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SayHelloActivityImpl implements SayHelloActivity { + private static final Logger log = LoggerFactory.getLogger(SayHelloActivityImpl.class); + + public String sayHello(String person) { + log.info("Saying hello to {}", person); + return "Hello, " + person; + } +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloV2WorkerRegistrar.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloV2WorkerRegistrar.java new file mode 100644 index 000000000000..50b9b25f4cea --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloV2WorkerRegistrar.java @@ -0,0 +1,22 @@ +package com.baeldung.temporal.workflows.hellov2; + +import com.baeldung.temporal.worker.TemporalWorkerRegistrar; +import com.baeldung.temporal.workflows.hellov2.activities.HelloV2ActivitiesImpl; +import io.temporal.worker.Worker; + +public class HelloV2WorkerRegistrar implements TemporalWorkerRegistrar { + + + private HelloV2WorkerRegistrar() { + } + + @Override + public void register(Worker worker) { + worker.registerWorkflowImplementationTypes(HelloWorkflowV2Impl.class); + worker.registerActivitiesImplementations(new HelloV2ActivitiesImpl()); + } + + public static HelloV2WorkerRegistrar newInstance() { + return new HelloV2WorkerRegistrar(); + } +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloWorkflowV2.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloWorkflowV2.java new file mode 100644 index 000000000000..5b5f98569706 --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloWorkflowV2.java @@ -0,0 +1,10 @@ +package com.baeldung.temporal.workflows.hellov2; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface HelloWorkflowV2 { + @WorkflowMethod + String hello(String person); +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloWorkflowV2Impl.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloWorkflowV2Impl.java new file mode 100644 index 000000000000..a4171ae3169e --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/HelloWorkflowV2Impl.java @@ -0,0 +1,45 @@ +package com.baeldung.temporal.workflows.hellov2; + +import com.baeldung.temporal.workflows.hellov2.activities.HelloV2Activities; +import io.temporal.activity.ActivityOptions; +import io.temporal.common.RetryOptions; +import io.temporal.workflow.Workflow; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Duration; + +public class HelloWorkflowV2Impl implements HelloWorkflowV2 { + + private static final Logger log = LoggerFactory.getLogger(HelloWorkflowV2Impl.class); + + + private final HelloV2Activities activity = Workflow.newActivityStub( + HelloV2Activities.class, + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(10)) + .setRetryOptions(RetryOptions.newBuilder() + .setMaximumAttempts(3) + .setInitialInterval(Duration.ofSeconds(1)) + .build()) + .build() + ); + + + @Override + public String hello(String person) { + + var info = Workflow.getInfo(); + + log.info("Running workflow for person {}: id={}, attempt={}", + person, + info.getWorkflowId(), + info.getAttempt()); + + var step1result = activity.sayHello(person); + var step2result = activity.sayGoodbye(person); + + return "Workflow OK"; + } + +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/activities/HelloV2Activities.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/activities/HelloV2Activities.java new file mode 100644 index 000000000000..dd32b2beaca1 --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/activities/HelloV2Activities.java @@ -0,0 +1,11 @@ +package com.baeldung.temporal.workflows.hellov2.activities; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; + +@ActivityInterface +public interface HelloV2Activities { + @ActivityMethod + String sayHello(String person); + String sayGoodbye(String person); +} diff --git a/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/activities/HelloV2ActivitiesImpl.java b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/activities/HelloV2ActivitiesImpl.java new file mode 100644 index 000000000000..85f827807f33 --- /dev/null +++ b/saas-modules/temporal/src/main/java/com/baeldung/temporal/workflows/hellov2/activities/HelloV2ActivitiesImpl.java @@ -0,0 +1,38 @@ +package com.baeldung.temporal.workflows.hellov2.activities; + +import io.temporal.activity.Activity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicLong; + +public class HelloV2ActivitiesImpl implements HelloV2Activities { + private static final Logger log = LoggerFactory.getLogger(HelloV2ActivitiesImpl.class); + + @Override + public String sayHello(String person) { + var info = Activity.getExecutionContext().getInfo(); + + log.info("Saying hello to {}, workflowId={}, attempt={}", person, + info.getWorkflowId(), + info.getAttempt()); + return "Step1 - OK"; + } + + @Override + public String sayGoodbye(String person) { + + var info = Activity.getExecutionContext().getInfo(); + + log.info("Saying goodbye to {}, workflowId={}, attempt={}", person, + info.getWorkflowId(), + info.getAttempt()); + + if ( info.getAttempt() == 1 ) { + throw new IllegalStateException("Simulating task failure"); + } + else { + return "Step2 - OK"; + } + } +} diff --git a/saas-modules/temporal/src/main/resources/logback.xml b/saas-modules/temporal/src/main/resources/logback.xml new file mode 100644 index 000000000000..adccaeb99807 --- /dev/null +++ b/saas-modules/temporal/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/saas-modules/temporal/src/test/java/com/baeldung/temporal/Hello2WorkerIntegrationTest.java b/saas-modules/temporal/src/test/java/com/baeldung/temporal/Hello2WorkerIntegrationTest.java new file mode 100644 index 000000000000..672513cc1f2a --- /dev/null +++ b/saas-modules/temporal/src/test/java/com/baeldung/temporal/Hello2WorkerIntegrationTest.java @@ -0,0 +1,86 @@ +package com.baeldung.temporal; + +import com.baeldung.temporal.workflows.hellov2.HelloV2WorkerRegistrar; +import com.baeldung.temporal.workflows.hellov2.HelloWorkflowV2; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class Hello2WorkerIntegrationTest { + private static final String QUEUE_NAME = "say-hello-queue"; + private static final Logger log = LoggerFactory.getLogger(Hello2WorkerIntegrationTest.class); + + private WorkerFactory factory; + + @BeforeEach + public void startWorker() { + + log.info("Creating worker..."); + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + this.factory = WorkerFactory.newInstance(client); + + var workerOptions = WorkerOptions.newBuilder() + .setUsingVirtualThreads(true) + .build(); + Worker worker = factory.newWorker(QUEUE_NAME,workerOptions); + + HelloV2WorkerRegistrar.newInstance() + .register(worker); + + log.info("Starting worker..."); + factory.start(); + log.info("Worker started."); + } + + @AfterEach + public void stopWorker() { + log.info("Stopping worker..."); + factory.shutdown(); + log.info("Worker stopped."); + } + + @Test + void givenPerson_whenSayHello_thenSuccess() { + + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + + var wfid = UUID.randomUUID().toString(); + + var workflow = client.newWorkflowStub( + HelloWorkflowV2.class, + WorkflowOptions.newBuilder() + .setTaskQueue(QUEUE_NAME) + .setWorkflowId(wfid) + .build() + ); + + + // Invoke workflow asynchronously. + var execution = WorkflowClient.start(workflow::hello,"Baeldung"); + log.info("Workflow started: id={}, runId={}", + execution.getWorkflowId(), + execution.getRunId()); + + // Create a blocking workflow using the execution's workflow id + var syncWorkflow = client.newWorkflowStub(HelloWorkflowV2.class,execution.getWorkflowId()); + + // The sync workflow stub will block until it completes. Notice that the call argument here is ignored! + assertEquals("Workflow OK", syncWorkflow.hello("ignored")); + + } + + + +} \ No newline at end of file diff --git a/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloV2WorkerUnitTest.java b/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloV2WorkerUnitTest.java new file mode 100644 index 000000000000..503165642ba5 --- /dev/null +++ b/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloV2WorkerUnitTest.java @@ -0,0 +1,68 @@ +package com.baeldung.temporal; + +import com.baeldung.temporal.workflows.hellov2.HelloWorkflowV2; +import com.baeldung.temporal.workflows.hellov2.HelloV2WorkerRegistrar; +import com.baeldung.temporal.workflows.hello.HelloWorkflow; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.worker.Worker; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HelloV2WorkerUnitTest { + private final Logger log = LoggerFactory.getLogger(HelloV2WorkerUnitTest.class); + private static final String QUEUE_NAME = "say-hello-queue"; + private TestWorkflowEnvironment testEnv; + private Worker worker; + private WorkflowClient client; + + @BeforeEach + void startWorker() { + log.info("Creating test environment..."); + testEnv = TestWorkflowEnvironment.newInstance(); + worker = testEnv.newWorker(QUEUE_NAME); + HelloV2WorkerRegistrar.newInstance().register(worker); + + client = testEnv.getWorkflowClient(); + } + + @AfterEach + void stopWorker() { + testEnv.close(); + } + + @Test + void givenPerson_whenSayHello_thenSuccess() throws Exception { + + // We must register all activities/worklows before starting the test environment + testEnv.start(); + + // Create workflow stub wich allow us to create workflow instances + var wfid = UUID.randomUUID().toString(); + var workflow = client.newWorkflowStub( + HelloWorkflowV2.class, + WorkflowOptions.newBuilder() + .setTaskQueue(QUEUE_NAME) + .setWorkflowId(wfid) + .build() + ); + + // Invoke workflow asynchronously. + var execution = WorkflowClient.start(workflow::hello,"Baeldung"); + + // Create a blocking workflow using tbe execution's workflow id + var syncWorkflow = client.newWorkflowStub(HelloWorkflow.class,execution.getWorkflowId()); + + // The sync workflow stub will block until it completes. Notice that the call argument here is ignored! + assertEquals("Workflow OK", syncWorkflow.hello("ignored")); + log.info("Test OK!"); + } +} \ No newline at end of file diff --git a/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloWorkerUnitTest.java b/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloWorkerUnitTest.java new file mode 100644 index 000000000000..f45640e6a83a --- /dev/null +++ b/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloWorkerUnitTest.java @@ -0,0 +1,94 @@ +package com.baeldung.temporal; + +import com.baeldung.temporal.workflows.hello.HelloWorkflow; +import com.baeldung.temporal.workflows.hello.HelloWorkflowRegistrar; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.worker.Worker; +import io.temporal.workflow.Workflow; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HelloWorkerUnitTest { + private final Logger log = LoggerFactory.getLogger(HelloWorkerUnitTest.class); + private static final String QUEUE_NAME = "say-hello-queue"; + + + private TestWorkflowEnvironment testEnv; + private Worker worker; + private WorkflowClient client; + + + @BeforeEach + public void startWorker() { + + log.info("Creating test environment..."); + testEnv = TestWorkflowEnvironment.newInstance(); + worker = testEnv.newWorker(QUEUE_NAME); + HelloWorkflowRegistrar.newInstance().register(worker); + client = testEnv.getWorkflowClient(); + + testEnv.start(); + } + + @AfterEach + public void stopWorker() { + testEnv.close(); + } + + @Test + void givenPerson_whenSayHelloAsync_thenSuccess() throws Exception { + + // Create workflow stub wich allow us to create workflow instances + var wfid = UUID.randomUUID().toString(); + var workflow = client.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(QUEUE_NAME) + .setWorkflowId(wfid) + .build() + ); + + // Invoke workflow asynchronously. + var execution = WorkflowClient.start(workflow::hello,"Baeldung"); + var workflowStub = client.newUntypedWorkflowStub(execution.getWorkflowId()); + + // Retrieve a CompletableFuture we can use to wait for the result. + var future = workflowStub.getResultAsync(String.class); + log.info("Waiting for workflow to complete..."); + var result = future.get(); + log.info("Workflow completed with result: {}", result); + assertEquals("Hello, Baeldung", result); + } + + @Test + void givenPerson_whenSayHelloSync_thenSuccess() throws Exception { + + // Create workflow stub wich allow us to create workflow instances + var wfid = UUID.randomUUID().toString(); + var workflow = client.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(QUEUE_NAME) + .setWorkflowId(wfid) + .build() + ); + + // Invoke workflow synchronously. + var result = workflow.hello("Baeldung"); + + // The sync workflow stub will block until it completes. Notice that the call argumento here is ignored! + assertEquals("Hello, Baeldung", result); + } +} \ No newline at end of file diff --git a/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloWorkflowIntegrationTest.java b/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloWorkflowIntegrationTest.java new file mode 100644 index 000000000000..2054ccf1d4cc --- /dev/null +++ b/saas-modules/temporal/src/test/java/com/baeldung/temporal/HelloWorkflowIntegrationTest.java @@ -0,0 +1,101 @@ +package com.baeldung.temporal; + +import com.baeldung.temporal.workflows.hello.HelloWorkflow; +import com.baeldung.temporal.workflows.hello.HelloWorkflowRegistrar; +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 org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HelloWorkflowIntegrationTest { + private static final String QUEUE_NAME = "say-hello-queue"; + private static final Logger log = LoggerFactory.getLogger(HelloWorkflowIntegrationTest.class); + + private WorkerFactory factory; + + @BeforeEach + public void startWorker() { + + log.info("Creating worker..."); + WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs(); + WorkflowClient client = WorkflowClient.newInstance(service); + this.factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(QUEUE_NAME); + + HelloWorkflowRegistrar.newInstance().register(worker); + + log.info("Starting worker..."); + factory.start(); + log.info("Worker started."); + } + + @AfterEach + public void stopWorker() { + log.info("Stopping worker..."); + factory.shutdown(); + log.info("Worker stopped."); + } + + @Test + void givenPerson_whenSayHello_thenSuccess() { + + var service = WorkflowServiceStubs.newLocalServiceStubs(); + var client = WorkflowClient.newInstance(service); + + var wfid = UUID.randomUUID().toString(); + + var workflow = client.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(QUEUE_NAME) + .setWorkflowId(wfid) + .build() + ); + + // Run the workflow synchronously + var result = workflow.hello("Baeldung"); + assertEquals("Hello, Baeldung", result); + } + + @Test + void givenPerson_whenSayHelloAsync_thenSuccess() throws ExecutionException, InterruptedException { + + var service = WorkflowServiceStubs.newLocalServiceStubs(); + var client = WorkflowClient.newInstance(service); + + var wfid = UUID.randomUUID().toString(); + + var workflow = client.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder() + .setTaskQueue(QUEUE_NAME) + .setWorkflowId(wfid) + .build() + ); + + var execution = WorkflowClient.start(workflow::hello,"Baeldung"); + + var workflowStub = client.newUntypedWorkflowStub(execution.getWorkflowId()); + + // Retrieve a CompletableFuture we can use to wait for the result. + var future = workflowStub.getResultAsync(String.class); + log.info("Waiting for workflow to complete..."); + var result = future.get(); + log.info("Workflow completed with result: {}", result); + assertEquals("Hello, Baeldung", result); + + } + +} \ No newline at end of file diff --git a/saas-modules/temporal/start-dev-server.sh b/saas-modules/temporal/start-dev-server.sh new file mode 100644 index 000000000000..299939d2462b --- /dev/null +++ b/saas-modules/temporal/start-dev-server.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec temporal server start-dev \ No newline at end of file