Skip to content

Commit 3486cf9

Browse files
committed
feat: Migrate 5 more recipe samples to new_samples with generator pattern
- childworkflow: Parent/child workflow relationships, ContinueAsNew - retryactivity: Retry policies and heartbeat progress tracking - query: Workflow query handlers for state inspection - localactivity: Fast local activities without server round-trips - sleep: Simple workflow.Sleep for delays Signed-off-by: Diana Zawadzki <[email protected]>
1 parent 2fd7776 commit 3486cf9

35 files changed

+1934
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<!-- THIS IS A GENERATED FILE -->
2+
<!-- PLEASE DO NOT EDIT -->
3+
4+
# Child Workflow 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+
## Child Workflow Sample
33+
34+
This sample demonstrates **parent-child workflow relationships** and the **ContinueAsNew** pattern.
35+
36+
### Start the Workflow
37+
38+
```bash
39+
cadence --env development \
40+
--domain cadence-samples \
41+
workflow start \
42+
--tl cadence-samples-worker \
43+
--et 60 \
44+
--workflow_type cadence_samples.ParentWorkflow
45+
```
46+
47+
### What Happens
48+
49+
```
50+
┌─────────────────────┐
51+
│ ParentWorkflow │
52+
└──────────┬──────────┘
53+
54+
│ ExecuteChildWorkflow
55+
56+
┌─────────────────────┐
57+
│ ChildWorkflow │──┐
58+
│ (run 1 of 5) │ │
59+
└─────────────────────┘ │
60+
│ │ ContinueAsNew
61+
▼ │
62+
┌─────────────────────┐ │
63+
│ ChildWorkflow │──┤
64+
│ (run 2 of 5) │ │
65+
└─────────────────────┘ │
66+
│ │
67+
... ...
68+
│ │
69+
▼ │
70+
┌─────────────────────┐ │
71+
│ ChildWorkflow │◀─┘
72+
│ (run 5 of 5) │
73+
└─────────────────────┘
74+
75+
│ Returns result
76+
77+
┌─────────────────────┐
78+
│ ParentWorkflow │
79+
│ completes │
80+
└─────────────────────┘
81+
```
82+
83+
1. Parent workflow starts a child workflow
84+
2. Child workflow uses `ContinueAsNew` to restart itself 5 times
85+
3. After 5 runs, child completes and returns result to parent
86+
87+
### Key Concept: Child Workflow Options
88+
89+
```go
90+
cwo := workflow.ChildWorkflowOptions{
91+
WorkflowID: childID,
92+
ExecutionStartToCloseTimeout: time.Minute,
93+
}
94+
ctx = workflow.WithChildOptions(ctx, cwo)
95+
96+
err := workflow.ExecuteChildWorkflow(ctx, ChildWorkflow, args...).Get(ctx, &result)
97+
```
98+
99+
### Key Concept: ContinueAsNew
100+
101+
```go
102+
// Instead of recursion (which grows history), use ContinueAsNew
103+
return "", workflow.NewContinueAsNewError(ctx, ChildWorkflow, newArgs...)
104+
```
105+
106+
ContinueAsNew starts a new workflow run with fresh history, avoiding unbounded history growth.
107+
108+
109+
## References
110+
111+
* The website: https://cadenceworkflow.io
112+
* Cadence's server: https://github.com/uber/cadence
113+
* Cadence's Go client: https://github.com/uber-go/cadence-client
114+
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"time"
7+
8+
"go.uber.org/cadence/workflow"
9+
"go.uber.org/zap"
10+
)
11+
12+
// ParentWorkflow demonstrates invoking a child workflow from a parent.
13+
// The parent waits for the child to complete before finishing.
14+
func ParentWorkflow(ctx workflow.Context) error {
15+
logger := workflow.GetLogger(ctx)
16+
logger.Info("ParentWorkflow started")
17+
18+
execution := workflow.GetInfo(ctx).WorkflowExecution
19+
// Parent can specify its own ID for child execution
20+
childID := fmt.Sprintf("child_workflow:%v", execution.RunID)
21+
22+
cwo := workflow.ChildWorkflowOptions{
23+
WorkflowID: childID,
24+
ExecutionStartToCloseTimeout: time.Minute,
25+
}
26+
ctx = workflow.WithChildOptions(ctx, cwo)
27+
28+
// Execute child workflow and wait for result
29+
var result string
30+
err := workflow.ExecuteChildWorkflow(ctx, ChildWorkflow, 0, 5).Get(ctx, &result)
31+
if err != nil {
32+
logger.Error("Child workflow failed", zap.Error(err))
33+
return err
34+
}
35+
36+
logger.Info("ParentWorkflow completed", zap.String("result", result))
37+
return nil
38+
}
39+
40+
// ChildWorkflow demonstrates ContinueAsNew pattern.
41+
// It runs multiple times, restarting itself with ContinueAsNew until runCount reaches 0.
42+
func ChildWorkflow(ctx workflow.Context, totalCount, runCount int) (string, error) {
43+
logger := workflow.GetLogger(ctx)
44+
logger.Info("ChildWorkflow started", zap.Int("totalCount", totalCount), zap.Int("runCount", runCount))
45+
46+
if runCount <= 0 {
47+
logger.Error("Invalid run count", zap.Int("runCount", runCount))
48+
return "", errors.New("invalid run count")
49+
}
50+
51+
totalCount++
52+
runCount--
53+
54+
if runCount == 0 {
55+
result := fmt.Sprintf("Child workflow completed after %d runs", totalCount)
56+
logger.Info("ChildWorkflow completed", zap.String("result", result))
57+
return result, nil
58+
}
59+
60+
// ContinueAsNew: start a new run with fresh history
61+
logger.Info("ChildWorkflow continuing as new", zap.Int("remainingRuns", runCount))
62+
return "", workflow.NewContinueAsNewError(ctx, ChildWorkflow, totalCount, runCount)
63+
}
64+
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: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
## Child Workflow Sample
2+
3+
This sample demonstrates **parent-child workflow relationships** and the **ContinueAsNew** pattern.
4+
5+
### Start the Workflow
6+
7+
```bash
8+
cadence --env development \
9+
--domain cadence-samples \
10+
workflow start \
11+
--tl cadence-samples-worker \
12+
--et 60 \
13+
--workflow_type cadence_samples.ParentWorkflow
14+
```
15+
16+
### What Happens
17+
18+
```
19+
┌─────────────────────┐
20+
│ ParentWorkflow │
21+
└──────────┬──────────┘
22+
23+
│ ExecuteChildWorkflow
24+
25+
┌─────────────────────┐
26+
│ ChildWorkflow │──┐
27+
│ (run 1 of 5) │ │
28+
└─────────────────────┘ │
29+
│ │ ContinueAsNew
30+
▼ │
31+
┌─────────────────────┐ │
32+
│ ChildWorkflow │──┤
33+
│ (run 2 of 5) │ │
34+
└─────────────────────┘ │
35+
│ │
36+
... ...
37+
│ │
38+
▼ │
39+
┌─────────────────────┐ │
40+
│ ChildWorkflow │◀─┘
41+
│ (run 5 of 5) │
42+
└─────────────────────┘
43+
44+
│ Returns result
45+
46+
┌─────────────────────┐
47+
│ ParentWorkflow │
48+
│ completes │
49+
└─────────────────────┘
50+
```
51+
52+
1. Parent workflow starts a child workflow
53+
2. Child workflow uses `ContinueAsNew` to restart itself 5 times
54+
3. After 5 runs, child completes and returns result to parent
55+
56+
### Key Concept: Child Workflow Options
57+
58+
```go
59+
cwo := workflow.ChildWorkflowOptions{
60+
WorkflowID: childID,
61+
ExecutionStartToCloseTimeout: time.Minute,
62+
}
63+
ctx = workflow.WithChildOptions(ctx, cwo)
64+
65+
err := workflow.ExecuteChildWorkflow(ctx, ChildWorkflow, args...).Get(ctx, &result)
66+
```
67+
68+
### Key Concept: ContinueAsNew
69+
70+
```go
71+
// Instead of recursion (which grows history), use ContinueAsNew
72+
return "", workflow.NewContinueAsNewError(ctx, ChildWorkflow, newArgs...)
73+
```
74+
75+
ContinueAsNew starts a new workflow run with fresh history, avoiding unbounded history growth.
76+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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: "Child Workflow",
8+
Workflows: []string{"ParentWorkflow", "ChildWorkflow"},
9+
Activities: []string{},
10+
}
11+
12+
template.GenerateAll(data)
13+
}
14+

new_samples/childworkflow/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)