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 eae382b1..829bfc9d 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 00000000..41cbba1f --- /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 00000000..ff8d0dd7 --- /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 00000000..96ff7696 --- /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. + * + *