Skip to content

Commit 2bf4224

Browse files
authored
Added updatabletimer sample (#15)
1 parent 5120387 commit 2bf4224

File tree

8 files changed

+325
-1
lines changed

8 files changed

+325
-1
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
3+
*
4+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
9+
* use this file except in compliance with the License. A copy of the License is
10+
* located at
11+
*
12+
* http://aws.amazon.com/apache2.0
13+
*
14+
* or in the "license" file accompanying this file. This file is distributed on
15+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
16+
* express or implied. See the License for the specific language governing
17+
* permissions and limitations under the License.
18+
*/
19+
20+
package io.temporal.samples.updatabletimer;
21+
22+
import io.temporal.workflow.QueryMethod;
23+
import io.temporal.workflow.SignalMethod;
24+
import io.temporal.workflow.WorkflowInterface;
25+
import io.temporal.workflow.WorkflowMethod;
26+
27+
@WorkflowInterface
28+
public interface DynamicSleepWorkflow {
29+
@WorkflowMethod
30+
void execute(long wakeUpTime);
31+
32+
@SignalMethod
33+
void updateWakeUpTime(long wakeUpTime);
34+
35+
@QueryMethod
36+
long getWakeUpTime();
37+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
3+
*
4+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
9+
* use this file except in compliance with the License. A copy of the License is
10+
* located at
11+
*
12+
* http://aws.amazon.com/apache2.0
13+
*
14+
* or in the "license" file accompanying this file. This file is distributed on
15+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
16+
* express or implied. See the License for the specific language governing
17+
* permissions and limitations under the License.
18+
*/
19+
20+
package io.temporal.samples.updatabletimer;
21+
22+
public class DynamicSleepWorkflowImpl implements DynamicSleepWorkflow {
23+
24+
private UpdatableTimer timer = new UpdatableTimer();
25+
26+
@Override
27+
public void execute(long wakeUpTime) {
28+
timer.sleepUntil(wakeUpTime);
29+
}
30+
31+
@Override
32+
public void updateWakeUpTime(long wakeUpTime) {
33+
timer.updateWakeUpTime(wakeUpTime);
34+
}
35+
36+
@Override
37+
public long getWakeUpTime() {
38+
return timer.getWakeUpTime();
39+
}
40+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
3+
*
4+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
9+
* use this file except in compliance with the License. A copy of the License is
10+
* located at
11+
*
12+
* http://aws.amazon.com/apache2.0
13+
*
14+
* or in the "license" file accompanying this file. This file is distributed on
15+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
16+
* express or implied. See the License for the specific language governing
17+
* permissions and limitations under the License.
18+
*/
19+
20+
package io.temporal.samples.updatabletimer;
21+
22+
import static io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker.DYNAMIC_SLEEP_WORKFLOW_ID;
23+
import static io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker.TASK_LIST;
24+
25+
import io.temporal.client.DuplicateWorkflowException;
26+
import io.temporal.client.WorkflowClient;
27+
import io.temporal.client.WorkflowOptions;
28+
import io.temporal.proto.common.WorkflowExecution;
29+
import io.temporal.proto.common.WorkflowIdReusePolicy;
30+
import io.temporal.serviceclient.WorkflowServiceStubs;
31+
import org.slf4j.Logger;
32+
import org.slf4j.LoggerFactory;
33+
34+
public class DynamicSleepWorkflowStarter {
35+
36+
private static final Logger logger = LoggerFactory.getLogger(DynamicSleepWorkflowStarter.class);
37+
38+
public static void main(String[] args) {
39+
WorkflowServiceStubs service = WorkflowServiceStubs.newInstance();
40+
WorkflowClient client = WorkflowClient.newInstance(service);
41+
42+
DynamicSleepWorkflow workflow =
43+
client.newWorkflowStub(
44+
DynamicSleepWorkflow.class,
45+
WorkflowOptions.newBuilder()
46+
.setTaskList(TASK_LIST)
47+
.setWorkflowId(DYNAMIC_SLEEP_WORKFLOW_ID)
48+
.setWorkflowIdReusePolicy(WorkflowIdReusePolicy.AllowDuplicate)
49+
.build());
50+
51+
try {
52+
// Start asynchronously
53+
WorkflowExecution execution =
54+
WorkflowClient.start(workflow::execute, System.currentTimeMillis() + 60000);
55+
logger.info("Workflow started: " + execution);
56+
} catch (DuplicateWorkflowException e) {
57+
logger.info("Workflow already running: " + e.getExecution());
58+
}
59+
}
60+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
3+
*
4+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
9+
* use this file except in compliance with the License. A copy of the License is
10+
* located at
11+
*
12+
* http://aws.amazon.com/apache2.0
13+
*
14+
* or in the "license" file accompanying this file. This file is distributed on
15+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
16+
* express or implied. See the License for the specific language governing
17+
* permissions and limitations under the License.
18+
*/
19+
20+
package io.temporal.samples.updatabletimer;
21+
22+
import io.temporal.client.WorkflowClient;
23+
import io.temporal.serviceclient.WorkflowServiceStubs;
24+
import io.temporal.worker.Worker;
25+
import io.temporal.worker.WorkerFactory;
26+
import org.slf4j.Logger;
27+
import org.slf4j.LoggerFactory;
28+
29+
public class DynamicSleepWorkflowWorker {
30+
31+
static final String TASK_LIST = "TimerUpdate";
32+
33+
private static final Logger logger = LoggerFactory.getLogger(DynamicSleepWorkflowWorker.class);
34+
/** Create just one workflow instance for the sake of the sample. */
35+
static final String DYNAMIC_SLEEP_WORKFLOW_ID = "DynamicSleepWorkflow";
36+
37+
public static void main(String[] args) {
38+
WorkflowServiceStubs service = WorkflowServiceStubs.newInstance();
39+
WorkflowClient client = WorkflowClient.newInstance(service);
40+
WorkerFactory factory = WorkerFactory.newInstance(client);
41+
final Worker worker = factory.newWorker(TASK_LIST);
42+
worker.registerWorkflowImplementationTypes(DynamicSleepWorkflowImpl.class);
43+
factory.start();
44+
logger.info("Worker started for task list: " + TASK_LIST);
45+
}
46+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Updatable Timer Sample
2+
3+
Demonstrates a helper class which relies on Workflow.await to implement a blocking sleep that can be updated
4+
at any moment.
5+
6+
The sample is composed of the three executables:
7+
8+
* `DynamicSleepWorkflowWorker` hosts the workflow code
9+
* `DynamicSleepWorkflowStarter` starts a workflow instance.
10+
* `WakeUpTimeUpdater` signals the workflow instance with the new time to wake up
11+
12+
###
13+
14+
First start the worker:
15+
16+
./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker
17+
18+
Then in a different terminal window start the workflow instance:
19+
20+
./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.DynamicSleepWorkflowStarter
21+
22+
Check the output of the worker window. The expected output is:
23+
24+
```bash
25+
10:38:56.282 [main] INFO i.t.s.timerupdate.DynamicSleepWorker - Worker started for task list: TimerUpdate
26+
10:39:07.359 [workflow-732875527] INFO i.t.s.t.DynamicSleepWorkflowImpl - sleepUntil: Thu May 28 10:40:06 PDT 2020
27+
10:39:07.360 [workflow-732875527] INFO i.t.s.t.DynamicSleepWorkflowImpl - Going to sleep for PT59.688S
28+
```
29+
Then run the updater as many times as you want to change timer to 10 seconds from now:
30+
31+
./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.WakeUpTimeUpdater
32+
./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.WakeUpTimeUpdater
33+
34+
Check the output of the worker window. The expected output is:
35+
36+
```bash
37+
10:39:12.934 [workflow-732875527] INFO i.t.s.t.DynamicSleepWorkflowImpl - Going to sleep for PT9.721S
38+
10:39:20.755 [workflow-732875527] INFO i.t.s.t.DynamicSleepWorkflowImpl - Going to sleep for PT9.733S
39+
10:39:30.772 [workflow-732875527] INFO i.t.s.t.DynamicSleepWorkflowImpl - sleepUntil completed
40+
```
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
3+
*
4+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
9+
* use this file except in compliance with the License. A copy of the License is
10+
* located at
11+
*
12+
* http://aws.amazon.com/apache2.0
13+
*
14+
* or in the "license" file accompanying this file. This file is distributed on
15+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
16+
* express or implied. See the License for the specific language governing
17+
* permissions and limitations under the License.
18+
*/
19+
20+
package io.temporal.samples.updatabletimer;
21+
22+
import io.temporal.workflow.Workflow;
23+
import java.time.Duration;
24+
import java.util.Date;
25+
import org.slf4j.Logger;
26+
27+
public final class UpdatableTimer {
28+
29+
private final Logger logger = Workflow.getLogger(DynamicSleepWorkflowImpl.class);
30+
31+
private long wakeUpTime;
32+
private boolean wakeUpTimeUpdated;
33+
34+
public void sleepUntil(long wakeUpTime) {
35+
logger.info("sleepUntil: " + new Date(wakeUpTime));
36+
this.wakeUpTime = wakeUpTime;
37+
do {
38+
wakeUpTimeUpdated = false;
39+
Duration sleepInterval = Duration.ofMillis(this.wakeUpTime - Workflow.currentTimeMillis());
40+
logger.info("Going to sleep for " + sleepInterval);
41+
if (!Workflow.await(sleepInterval, () -> wakeUpTimeUpdated)) {
42+
break;
43+
}
44+
} while (wakeUpTimeUpdated);
45+
logger.info("sleepUntil completed");
46+
}
47+
48+
public void updateWakeUpTime(long wakeUpTime) {
49+
this.wakeUpTime = wakeUpTime;
50+
this.wakeUpTimeUpdated = true;
51+
}
52+
53+
public long getWakeUpTime() {
54+
return wakeUpTime;
55+
}
56+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
3+
*
4+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
9+
* use this file except in compliance with the License. A copy of the License is
10+
* located at
11+
*
12+
* http://aws.amazon.com/apache2.0
13+
*
14+
* or in the "license" file accompanying this file. This file is distributed on
15+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
16+
* express or implied. See the License for the specific language governing
17+
* permissions and limitations under the License.
18+
*/
19+
20+
package io.temporal.samples.updatabletimer;
21+
22+
import static io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker.DYNAMIC_SLEEP_WORKFLOW_ID;
23+
24+
import io.temporal.client.WorkflowClient;
25+
import io.temporal.serviceclient.WorkflowServiceStubs;
26+
import org.slf4j.Logger;
27+
import org.slf4j.LoggerFactory;
28+
29+
public class WakeUpTimeUpdater {
30+
31+
private static final Logger logger = LoggerFactory.getLogger(WakeUpTimeUpdater.class);
32+
33+
public static void main(String[] args) {
34+
WorkflowServiceStubs service = WorkflowServiceStubs.newInstance();
35+
WorkflowClient client = WorkflowClient.newInstance(service);
36+
37+
// Create a stub that points to an existing workflow with the given ID
38+
DynamicSleepWorkflow workflow =
39+
client.newWorkflowStub(DynamicSleepWorkflow.class, DYNAMIC_SLEEP_WORKFLOW_ID);
40+
41+
// signal workflow about the wake up time change
42+
workflow.updateWakeUpTime(System.currentTimeMillis() + 10000);
43+
logger.info("Updated wake up time to 10 seconds from now");
44+
}
45+
}

src/main/resources/logback.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
</encoder>
2727
</appender>
2828
<logger name="io.grpc.netty" level="INFO"/>
29-
<root level="WARN">
29+
<root level="INFO">
3030
<appender-ref ref="STDOUT" />
3131
</root>
3232
</configuration>

0 commit comments

Comments
 (0)