Skip to content

Commit 019a42d

Browse files
committed
Add self-contained samples: cancelactivity, delaystart, dynamic, splitmerge, signalcounter
Signed-off-by: Diana Zawadzki <[email protected]>
1 parent 798a5b9 commit 019a42d

35 files changed

+1878
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<!-- THIS IS A GENERATED FILE -->
2+
<!-- PLEASE DO NOT EDIT -->
3+
4+
# Cancel Activity Sample
5+
6+
## Prerequisites
7+
8+
0. Install Cadence CLI. See instruction [here](https://cadenceworkflow.io/docs/cli/).
9+
1. Run the Cadence server:
10+
1. Clone the [Cadence](https://github.com/cadence-workflow/cadence) repository if you haven't done already: `git clone https://github.com/cadence-workflow/cadence.git`
11+
2. Run `docker compose -f docker/docker-compose.yml up` to start Cadence server
12+
3. See more details at https://github.com/uber/cadence/blob/master/README.md
13+
2. Once everything is up and running in Docker, open [localhost:8088](localhost:8088) to view Cadence UI.
14+
3. Register the `cadence-samples` domain:
15+
16+
```bash
17+
cadence --env development --domain cadence-samples domain register
18+
```
19+
20+
Refresh the [domains page](http://localhost:8088/domains) from step 2 to verify `cadence-samples` is registered.
21+
22+
## Steps to run sample
23+
24+
Inside the folder this sample is defined, run the following command:
25+
26+
```bash
27+
go run .
28+
```
29+
30+
This will call the main function in main.go which starts the worker, which will be execute the sample workflow code
31+
32+
## How It Works
33+
34+
This sample demonstrates graceful workflow cancellation with cleanup:
35+
36+
```
37+
┌──────────────────────┐
38+
│ CancelWorkflow │
39+
│ │
40+
│ ┌────────────────┐ │ Cancel Signal
41+
│ │ LongRunning │◀─┼─────────────────────
42+
│ │ Activity │ │
43+
│ │ (heartbeating) │ │
44+
│ └───────┬────────┘ │
45+
│ │ │
46+
│ On Cancel: │
47+
│ ▼ │
48+
│ ┌────────────────┐ │
49+
│ │ CleanupActivity│ │ ← Runs in disconnected context
50+
│ └────────────────┘ │
51+
└──────────────────────┘
52+
```
53+
54+
Key concepts:
55+
- **WaitForCancellation**: Activity option that waits for activity to acknowledge cancel
56+
- **NewDisconnectedContext**: Creates a context unaffected by workflow cancellation
57+
- **IsCanceledError**: Check if an error is due to cancellation
58+
59+
## Running the Sample
60+
61+
Start the worker:
62+
```bash
63+
go run .
64+
```
65+
66+
Trigger a workflow:
67+
```bash
68+
cadence --env development \
69+
--domain cadence-samples \
70+
workflow start \
71+
--workflow_type cadence_samples.CancelWorkflow \
72+
--tl cadence-samples-worker \
73+
--et 600
74+
```
75+
76+
Cancel the workflow (copy workflow ID from above):
77+
```bash
78+
cadence --env development \
79+
--domain cadence-samples \
80+
workflow cancel \
81+
--wid <workflow_id>
82+
```
83+
84+
Watch the worker logs to see the cleanup activity run.
85+
86+
## References
87+
88+
* The website: https://cadenceworkflow.io
89+
* Cadence's server: https://github.com/uber/cadence
90+
* Cadence's Go client: https://github.com/uber-go/cadence-client
91+
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"go.uber.org/cadence"
9+
"go.uber.org/cadence/activity"
10+
"go.uber.org/cadence/workflow"
11+
"go.uber.org/zap"
12+
)
13+
14+
/**
15+
* This is the cancel activity workflow sample.
16+
*/
17+
18+
// ApplicationName is the task list for this sample
19+
const ApplicationName = "cancelGroup"
20+
21+
// CancelWorkflow workflow decider
22+
func CancelWorkflow(ctx workflow.Context) (retError error) {
23+
ao := workflow.ActivityOptions{
24+
ScheduleToStartTimeout: time.Minute,
25+
StartToCloseTimeout: time.Minute * 30,
26+
HeartbeatTimeout: time.Second * 5,
27+
WaitForCancellation: true,
28+
}
29+
ctx = workflow.WithActivityOptions(ctx, ao)
30+
logger := workflow.GetLogger(ctx)
31+
logger.Info("cancel workflow started")
32+
33+
defer func() {
34+
if cadence.IsCanceledError(retError) {
35+
// When workflow is canceled, it has to get a new disconnected context to execute any activities
36+
newCtx, _ := workflow.NewDisconnectedContext(ctx)
37+
err := workflow.ExecuteActivity(newCtx, CleanupActivity).Get(ctx, nil)
38+
if err != nil {
39+
logger.Error("Cleanup activity failed", zap.Error(err))
40+
retError = err
41+
return
42+
}
43+
retError = nil
44+
logger.Info("Workflow completed.")
45+
}
46+
}()
47+
48+
var result string
49+
err := workflow.ExecuteActivity(ctx, LongRunningActivity).Get(ctx, &result)
50+
if err != nil && !cadence.IsCanceledError(err) {
51+
logger.Error("Error from LongRunningActivity", zap.Error(err))
52+
return err
53+
}
54+
logger.Info(fmt.Sprintf("LongRunningActivity returns %v, %v", result, err))
55+
56+
// Execute activity using a canceled ctx,
57+
// activity won't be scheduled and an cancelled error will be returned
58+
err = workflow.ExecuteActivity(ctx, SkippedActivity).Get(ctx, nil)
59+
if err != nil && !cadence.IsCanceledError(err) {
60+
logger.Error("Error from SkippedActivity", zap.Error(err))
61+
}
62+
63+
return err
64+
}
65+
66+
func LongRunningActivity(ctx context.Context) (string, error) {
67+
logger := activity.GetLogger(ctx)
68+
logger.Info("activity started, to cancel workflow, use ./cancelactivity -m cancel -w <WorkflowID> or CLI: 'cadence --do default wf cancel -w <WorkflowID>' to cancel")
69+
for {
70+
select {
71+
case <-time.After(1 * time.Second):
72+
logger.Info("heartbeating...")
73+
activity.RecordHeartbeat(ctx, "")
74+
case <-ctx.Done():
75+
logger.Info("context is cancelled")
76+
// returned canceled error here so that in workflow history we can see ActivityTaskCanceled event
77+
// or if not cancelled, return timeout error
78+
return "I am canceled by Done", ctx.Err()
79+
}
80+
}
81+
}
82+
83+
func CleanupActivity(ctx context.Context) error {
84+
logger := activity.GetLogger(ctx)
85+
logger.Info("CleanupActivity started")
86+
return nil
87+
}
88+
89+
func SkippedActivity(ctx context.Context) error {
90+
logger := activity.GetLogger(ctx)
91+
logger.Info("this activity will be skipped due to cancellation")
92+
return nil
93+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!-- THIS IS A GENERATED FILE -->
2+
<!-- PLEASE DO NOT EDIT -->
3+
4+
# Sample Generator
5+
6+
This folder is NOT part of the actual sample. It exists only for contributors who work on this sample. Please disregard it if you are trying to learn about Cadence.
7+
8+
To create a better learning experience for Cadence users, each sample folder is designed to be self contained. Users can view every part of writing and running workflows, including:
9+
10+
* Cadence client initialization
11+
* Worker with workflow and activity registrations
12+
* Workflow starter
13+
* and the workflow code itself
14+
15+
Some samples may have more or fewer parts depending on what they need to demonstrate.
16+
17+
In most cases, the workflow code (e.g. `workflow.go`) is the part that users care about. The rest is boilerplate needed to run that workflow. For each sample folder, the workflow code should be written by hand. The boilerplate can be generated. Keeping all parts inside one folder gives early learners more value because they can see everything together rather than jumping across directories.
18+
19+
## Contributing
20+
21+
* When creating a new sample, follow the steps mentioned in the README file in the main samples folder.
22+
* To update the sample workflow code, edit the workflow file directly.
23+
* To update the worker, client, or other boilerplate logic, edit the generator file. If your change applies to all samples, update the common generator file inside the `template` folder. Edit the generator file in this folder only when the change should affect this sample alone.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
## How It Works
2+
3+
This sample demonstrates graceful workflow cancellation with cleanup:
4+
5+
```
6+
┌──────────────────────┐
7+
│ CancelWorkflow │
8+
│ │
9+
│ ┌────────────────┐ │ Cancel Signal
10+
│ │ LongRunning │◀─┼─────────────────────
11+
│ │ Activity │ │
12+
│ │ (heartbeating) │ │
13+
│ └───────┬────────┘ │
14+
│ │ │
15+
│ On Cancel: │
16+
│ ▼ │
17+
│ ┌────────────────┐ │
18+
│ │ CleanupActivity│ │ ← Runs in disconnected context
19+
│ └────────────────┘ │
20+
└──────────────────────┘
21+
```
22+
23+
Key concepts:
24+
- **WaitForCancellation**: Activity option that waits for activity to acknowledge cancel
25+
- **NewDisconnectedContext**: Creates a context unaffected by workflow cancellation
26+
- **IsCanceledError**: Check if an error is due to cancellation
27+
28+
## Running the Sample
29+
30+
Start the worker:
31+
```bash
32+
go run .
33+
```
34+
35+
Trigger a workflow:
36+
```bash
37+
cadence --env development \
38+
--domain cadence-samples \
39+
workflow start \
40+
--workflow_type cadence_samples.CancelWorkflow \
41+
--tl cadence-samples-worker \
42+
--et 600
43+
```
44+
45+
Cancel the workflow (copy workflow ID from above):
46+
```bash
47+
cadence --env development \
48+
--domain cadence-samples \
49+
workflow cancel \
50+
--wid <workflow_id>
51+
```
52+
53+
Watch the worker logs to see the cleanup activity run.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package main
2+
3+
import "github.com/uber-common/cadence-samples/new_samples/template"
4+
5+
func main() {
6+
data := template.TemplateData{
7+
SampleName: "Cancel Activity",
8+
Workflows: []string{"CancelWorkflow"},
9+
Activities: []string{"LongRunningActivity", "CleanupActivity", "SkippedActivity"},
10+
}
11+
template.GenerateAll(data)
12+
}

new_samples/cancelactivity/main.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// THIS IS A GENERATED FILE
2+
// PLEASE DO NOT EDIT
3+
4+
package main
5+
6+
import (
7+
"fmt"
8+
"os"
9+
"os/signal"
10+
"syscall"
11+
)
12+
13+
func main() {
14+
StartWorker()
15+
16+
done := make(chan os.Signal, 1)
17+
signal.Notify(done, syscall.SIGINT)
18+
fmt.Println("Cadence worker started, press ctrl+c to terminate...")
19+
<-done
20+
}

0 commit comments

Comments
 (0)