From 143902cba3e14aa11f3b90784baf53406c329fd2 Mon Sep 17 00:00:00 2001 From: Maxim Fateev Date: Tue, 9 Jun 2020 16:12:45 -0700 Subject: [PATCH] Samples used during presentations (#5) * Added moneytransfer and moneybatch samples * Removed excessive comments * Fixed errors after merge * Fixed money samples --- .../temporal/samples/moneybatch/Account.java | 30 ++++++ .../moneybatch/AccountActivityWorker.java | 45 ++++++++ .../samples/moneybatch/AccountImpl.java | 37 +++++++ .../moneybatch/AccountTransferWorker.java | 41 +++++++ .../moneybatch/AccountTransferWorkflow.java | 41 +++++++ .../AccountTransferWorkflowImpl.java | 74 +++++++++++++ .../io/temporal/samples/moneybatch/README.md | 17 +++ .../samples/moneybatch/TransferRequester.java | 59 +++++++++++ .../samples/moneytransfer/Account.java | 30 ++++++ .../moneytransfer/AccountActivityWorker.java | 48 +++++++++ .../samples/moneytransfer/AccountImpl.java | 39 +++++++ .../moneytransfer/AccountTransferWorker.java | 47 ++++++++ .../AccountTransferWorkflow.java | 29 +++++ .../AccountTransferWorkflowImpl.java | 41 +++++++ .../moneytransfer/TransferRequester.java | 57 ++++++++++ .../updatabletimer/UpdatableTimer.java | 6 +- .../moneybatch/TransferWorkflowTest.java | 100 ++++++++++++++++++ .../moneytransfer/TransferWorkflowTest.java | 70 ++++++++++++ 18 files changed, 808 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/temporal/samples/moneybatch/Account.java create mode 100644 src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java create mode 100644 src/main/java/io/temporal/samples/moneybatch/AccountImpl.java create mode 100644 src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java create mode 100644 src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java create mode 100644 src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java create mode 100644 src/main/java/io/temporal/samples/moneybatch/README.md create mode 100644 src/main/java/io/temporal/samples/moneybatch/TransferRequester.java create mode 100644 src/main/java/io/temporal/samples/moneytransfer/Account.java create mode 100644 src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java create mode 100644 src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java create mode 100644 src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java create mode 100644 src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java create mode 100644 src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java create mode 100644 src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java create mode 100644 src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java create mode 100644 src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java diff --git a/src/main/java/io/temporal/samples/moneybatch/Account.java b/src/main/java/io/temporal/samples/moneybatch/Account.java new file mode 100644 index 00000000..98565e90 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneybatch/Account.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.moneybatch; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface Account { + + void deposit(String accountId, String referenceId, int amountCents); + + void withdraw(String accountId, String referenceId, int amountCents); +} diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java b/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java new file mode 100644 index 00000000..0b93a630 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.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.moneybatch; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class AccountActivityWorker { + + static final String TASK_LIST = "Account"; + + @SuppressWarnings("CatchAndPrintStackTrace") + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newInstance(); + WorkflowClient client = WorkflowClient.newInstance(service); + + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(TASK_LIST); + + Account account = new AccountImpl(); + worker.registerActivitiesImplementations(account); + + factory.start(); + System.out.println("Activity Worker started for task list: " + TASK_LIST); + } +} diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java b/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java new file mode 100644 index 00000000..1e03f516 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneybatch/AccountImpl.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.moneybatch; + +public class AccountImpl implements Account { + @Override + public void deposit(String accountId, String referenceId, int amountCents) { + System.out.printf( + "Deposit to %s of %d cents requested. ReferenceId=%s\n", + accountId, amountCents, referenceId); + // throw new RuntimeException("simulated"); // Uncomment to simulate failure + } + + @Override + public void withdraw(String accountId, String referenceId, int amountCents) { + System.out.printf( + "Withdraw to %s of %d cents requested. ReferenceId=%s\n", + accountId, amountCents, referenceId); + } +} diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java b/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java new file mode 100644 index 00000000..02413ab5 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.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.moneybatch; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class AccountTransferWorker { + + @SuppressWarnings("CatchAndPrintStackTrace") + public static void main(String[] args) { + WorkflowServiceStubs service = WorkflowServiceStubs.newInstance(); + WorkflowClient client = WorkflowClient.newInstance(service); + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker(AccountActivityWorker.TASK_LIST); + worker.registerWorkflowImplementationTypes(AccountTransferWorkflowImpl.class); + + factory.start(); + System.out.println("Worker started for task list: " + AccountActivityWorker.TASK_LIST); + } +} diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java b/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java new file mode 100644 index 00000000..a3278cb7 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.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.moneybatch; + +import io.temporal.workflow.QueryMethod; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface AccountTransferWorkflow { + + @WorkflowMethod + void deposit(String toAccountId, int batchSize); + + @SignalMethod + void withdraw(String fromAccountId, String referenceId, int amountCents); + + @QueryMethod + int getBalance(); + + @QueryMethod + int getCount(); +} diff --git a/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java b/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.java new file mode 100644 index 00000000..3fa6845b --- /dev/null +++ b/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflowImpl.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.moneybatch; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.RetryOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.HashSet; +import java.util.Set; + +public class AccountTransferWorkflowImpl implements AccountTransferWorkflow { + + private final ActivityOptions options = + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(5)) + .setScheduleToStartTimeout(Duration.ofHours(1)) + .setRetryOptions( + RetryOptions.newBuilder() + .setInitialInterval(Duration.ofSeconds(1)) + .setMaximumInterval(Duration.ofSeconds(10)) + .build()) + .build(); + + private final Account account = Workflow.newActivityStub(Account.class, options); + + private Set references = new HashSet<>(); + private int balance; + private int count; + + @Override + public void deposit(String toAccount, int batchSize) { + Workflow.await(() -> count == batchSize); + String referenceId = Workflow.randomUUID().toString(); + account.deposit(toAccount, referenceId, balance); + } + + @Override + public void withdraw(String fromAccountId, String referenceId, int amountCents) { + if (!references.add(referenceId)) { + return; // duplicate + } + account.withdraw(fromAccountId, referenceId, amountCents); + balance += amountCents; + count++; + } + + @Override + public int getBalance() { + return balance; + } + + @Override + public int getCount() { + return count; + } +} diff --git a/src/main/java/io/temporal/samples/moneybatch/README.md b/src/main/java/io/temporal/samples/moneybatch/README.md new file mode 100644 index 00000000..05695aaa --- /dev/null +++ b/src/main/java/io/temporal/samples/moneybatch/README.md @@ -0,0 +1,17 @@ +# Demonstrates Signal Batching + +The sample demonstrates a situation when a single deposit should be initiated for multiple +withdrawals. 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 a more complex criteria like a +specific time or accumulated amount. + +The sample also demonstrates _signal with start_ way of starting workflows. If workflow is already +running it just receives a signal. If it is not running then it is started first and then signal is +delivered to it. You can think about _signal with start_ as a lazy way to create workflows when +signalling them. + +To run a worker that hosts the workflow code execute: + + + + diff --git a/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java b/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java new file mode 100644 index 00000000..394a3946 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneybatch/TransferRequester.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.moneybatch; + +import io.temporal.client.BatchRequest; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import java.util.Random; +import java.util.UUID; + +public class TransferRequester { + + /** Number of withdrawals to batch */ + public static final int BATCH_SIZE = 3; + + @SuppressWarnings("CatchAndPrintStackTrace") + public static void main(String[] args) { + String reference = UUID.randomUUID().toString(); + int amountCents = (new Random().nextInt(5) + 1) * 25; + WorkflowServiceStubs service = WorkflowServiceStubs.newInstance(); + WorkflowClient workflowClient = WorkflowClient.newInstance(service); + + String from = "account1"; + String to = "account2"; + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setTaskList(AccountActivityWorker.TASK_LIST) + .setWorkflowId(to) + .build(); + AccountTransferWorkflow transferWorkflow = + workflowClient.newWorkflowStub(AccountTransferWorkflow.class, options); + // Signal with start sends a signal to a workflow starting it if not yet running + BatchRequest request = workflowClient.newSignalWithStartRequest(); + request.add(transferWorkflow::deposit, to, BATCH_SIZE); + request.add(transferWorkflow::withdraw, from, reference, amountCents); + workflowClient.signalWithStart(request); + + System.out.printf("Transfer of %d cents from %s to %s requested", amountCents, from, to); + System.exit(0); + } +} diff --git a/src/main/java/io/temporal/samples/moneytransfer/Account.java b/src/main/java/io/temporal/samples/moneytransfer/Account.java new file mode 100644 index 00000000..507ceb53 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneytransfer/Account.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.moneytransfer; + +import io.temporal.activity.ActivityInterface; + +@ActivityInterface +public interface Account { + + void deposit(String accountId, String referenceId, int amountCents); + + void withdraw(String accountId, String referenceId, int amountCents); +} diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java b/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java new file mode 100644 index 00000000..29196ca8 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.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.moneytransfer; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class AccountActivityWorker { + + static final String TASK_LIST = "AcccountTransfer"; + + @SuppressWarnings("CatchAndPrintStackTrace") + public static void main(String[] args) { + // gRPC stubs wrapper that talks to the local docker instance of temporal service. + WorkflowServiceStubs service = WorkflowServiceStubs.newInstance(); + // 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 lists + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker worker = factory.newWorker(TASK_LIST); + Account account = new AccountImpl(); + worker.registerActivitiesImplementations(account); + + // Start all workers created by this factory. + factory.start(); + System.out.println("Activity Worker started for task list: " + TASK_LIST); + } +} diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java b/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java new file mode 100644 index 00000000..6ff9678e --- /dev/null +++ b/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.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.moneytransfer; + +public class AccountImpl implements Account { + + @Override + public void withdraw(String accountId, String referenceId, int amountCents) { + System.out.printf( + "Withdraw to %s of %d cents requested. ReferenceId=%s\n", + accountId, amountCents, referenceId); + // throw new RuntimeException("simulated"); + } + + @Override + public void deposit(String accountId, String referenceId, int amountCents) { + System.out.printf( + "Deposit to %s of %d cents requested. ReferenceId=%s\n", + accountId, amountCents, referenceId); + // throw new RuntimeException("simulated"); + } +} diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java b/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java new file mode 100644 index 00000000..ac2ec0bb --- /dev/null +++ b/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.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.moneytransfer; + +import static io.temporal.samples.moneytransfer.AccountActivityWorker.TASK_LIST; + +import io.temporal.client.WorkflowClient; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class AccountTransferWorker { + + @SuppressWarnings("CatchAndPrintStackTrace") + public static void main(String[] args) { + // Get worker to poll the common task list. + // gRPC stubs wrapper that talks to the local docker instance of temporal service. + WorkflowServiceStubs service = WorkflowServiceStubs.newInstance(); + // 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 lists + WorkerFactory factory = WorkerFactory.newInstance(client); + Worker workerForCommonTaskList = factory.newWorker(TASK_LIST); + workerForCommonTaskList.registerWorkflowImplementationTypes(AccountTransferWorkflowImpl.class); + // Start all workers created by this factory. + factory.start(); + System.out.println("Worker started for task list: " + TASK_LIST); + } +} diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java b/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java new file mode 100644 index 00000000..554ea54a --- /dev/null +++ b/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.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.moneytransfer; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface AccountTransferWorkflow { + @WorkflowMethod + void transfer(String fromAccountId, String toAccountId, String referenceId, int amountCents); +} diff --git a/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java b/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java new file mode 100644 index 00000000..32202aff --- /dev/null +++ b/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.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.moneytransfer; + +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Workflow; +import java.time.Duration; + +public class AccountTransferWorkflowImpl implements AccountTransferWorkflow { + + private final ActivityOptions options = + ActivityOptions.newBuilder() + .setStartToCloseTimeout(Duration.ofSeconds(5)) + .setScheduleToStartTimeout(Duration.ofMinutes(10)) + .build(); + private final Account account = Workflow.newActivityStub(Account.class, options); + + @Override + public void transfer( + String fromAccountId, String toAccountId, String referenceId, int amountCents) { + account.withdraw(fromAccountId, referenceId, amountCents); + account.deposit(toAccountId, referenceId, amountCents); + } +} diff --git a/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java b/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java new file mode 100644 index 00000000..2e60eb60 --- /dev/null +++ b/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.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.moneytransfer; + +import static io.temporal.samples.moneytransfer.AccountActivityWorker.TASK_LIST; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import java.util.Random; +import java.util.UUID; + +public class TransferRequester { + + @SuppressWarnings("CatchAndPrintStackTrace") + public static void main(String[] args) { + String reference; + int amountCents; + if (args.length == 0) { + reference = UUID.randomUUID().toString(); + amountCents = new Random().nextInt(5000); + } else { + reference = args[0]; + amountCents = Integer.parseInt(args[1]); + } + WorkflowServiceStubs service = WorkflowServiceStubs.newInstance(); + // client that can be used to start and signal workflows + WorkflowClient workflowClient = WorkflowClient.newInstance(service); + + // now we can start running instances of our saga - its state will be persisted + WorkflowOptions options = WorkflowOptions.newBuilder().setTaskList(TASK_LIST).build(); + AccountTransferWorkflow transferWorkflow = + workflowClient.newWorkflowStub(AccountTransferWorkflow.class, options); + String from = "account1"; + String to = "account2"; + WorkflowClient.start(transferWorkflow::transfer, from, to, reference, amountCents); + System.out.printf("Transfer of %d cents from %s to %s requested", amountCents, from, to); + System.exit(0); + } +} diff --git a/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java b/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java index a4dfda47..847e826d 100644 --- a/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java +++ b/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java @@ -26,7 +26,7 @@ public final class UpdatableTimer { - private final Logger logger = Workflow.getLogger(DynamicSleepWorkflowImpl.class); + private final Logger logger = Workflow.getLogger(UpdatableTimer.class); private long wakeUpTime; private boolean wakeUpTimeUpdated; @@ -34,14 +34,14 @@ public final class UpdatableTimer { public void sleepUntil(long wakeUpTime) { logger.info("sleepUntil: " + new Date(wakeUpTime)); this.wakeUpTime = wakeUpTime; - do { + while (true) { wakeUpTimeUpdated = false; Duration sleepInterval = Duration.ofMillis(this.wakeUpTime - Workflow.currentTimeMillis()); logger.info("Going to sleep for " + sleepInterval); if (!Workflow.await(sleepInterval, () -> wakeUpTimeUpdated)) { break; } - } while (wakeUpTimeUpdated); + } logger.info("sleepUntil completed"); } diff --git a/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java b/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java new file mode 100644 index 00000000..957b7e05 --- /dev/null +++ b/src/test/java/io/temporal/samples/moneybatch/TransferWorkflowTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved + * + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 io.temporal.samples.moneybatch.AccountActivityWorker.TASK_LIST; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.worker.Worker; +import java.util.Random; +import java.util.UUID; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +public class TransferWorkflowTest { + + private TestWorkflowEnvironment testEnv; + private Worker worker; + private WorkflowClient workflowClient; + + /** Prints a history of the workflow under test in case of a test failure. */ + @Rule + public TestWatcher watchman = + new TestWatcher() { + @Override + protected void failed(Throwable e, Description description) { + if (testEnv != null) { + System.err.println(testEnv.getDiagnostics()); + testEnv.close(); + } + } + }; + + @Before + public void setUp() { + testEnv = TestWorkflowEnvironment.newInstance(); + worker = testEnv.newWorker(TASK_LIST); + worker.registerWorkflowImplementationTypes(AccountTransferWorkflowImpl.class); + + workflowClient = testEnv.getWorkflowClient(); + } + + @After + public void tearDown() { + testEnv.close(); + } + + @Test + public void testTransfer() { + Account activities = mock(Account.class); + worker.registerActivitiesImplementations(activities); + testEnv.start(); + + String from = "account1"; + String to = "account2"; + int batchSize = 5; + WorkflowOptions options = + WorkflowOptions.newBuilder().setTaskList(TASK_LIST).setWorkflowId(to).build(); + AccountTransferWorkflow transferWorkflow = + workflowClient.newWorkflowStub(AccountTransferWorkflow.class, options); + WorkflowClient.start(transferWorkflow::deposit, to, batchSize); + Random random = new Random(); + int total = 0; + for (int i = 0; i < batchSize; i++) { + int amountCents = random.nextInt(1000); + transferWorkflow.withdraw(from, UUID.randomUUID().toString(), amountCents); + total += amountCents; + } + // Wait for workflow to finish + WorkflowStub.fromTyped(transferWorkflow).getResult(Void.class); + verify(activities).deposit(eq("account2"), any(), eq(total)); + } +} diff --git a/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java b/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.java new file mode 100644 index 00000000..d121ad4b --- /dev/null +++ b/src/test/java/io/temporal/samples/moneytransfer/TransferWorkflowTest.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.moneytransfer; + +import static io.temporal.samples.moneytransfer.AccountActivityWorker.TASK_LIST; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.worker.Worker; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class TransferWorkflowTest { + + private TestWorkflowEnvironment testEnv; + private Worker worker; + private WorkflowClient workflowClient; + + @Before + public void setUp() { + testEnv = TestWorkflowEnvironment.newInstance(); + worker = testEnv.newWorker(TASK_LIST); + worker.registerWorkflowImplementationTypes(AccountTransferWorkflowImpl.class); + + workflowClient = testEnv.getWorkflowClient(); + } + + @After + public void tearDown() { + testEnv.close(); + } + + @Test + public void testTransfer() { + Account activities = mock(Account.class); + worker.registerActivitiesImplementations(activities); + testEnv.start(); + WorkflowOptions options = WorkflowOptions.newBuilder().setTaskList(TASK_LIST).build(); + AccountTransferWorkflow workflow = + workflowClient.newWorkflowStub(AccountTransferWorkflow.class, options); + long starty = testEnv.currentTimeMillis(); + workflow.transfer("account1", "account2", "reference1", 123); + verify(activities).withdraw(eq("account1"), eq("reference1"), eq(123)); + verify(activities).deposit(eq("account2"), eq("reference1"), eq(123)); + long duration = testEnv.currentTimeMillis() - starty; + System.out.println("Duration: " + duration); + } +}