Skip to content

Commit 398fcb1

Browse files
committed
Merge branch 'migrate-recipes-samples' into restructure-new-samples
2 parents 27fd027 + 04acfd8 commit 398fcb1

35 files changed

+2184
-0
lines changed

new_samples/branch/README.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<!-- THIS IS A GENERATED FILE -->
2+
<!-- PLEASE DO NOT EDIT -->
3+
4+
# Branch 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+
## Branch Workflow
33+
34+
This sample demonstrates **parallel activity execution** - running multiple activities concurrently.
35+
36+
### Start Branch 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.BranchWorkflow
45+
```
46+
47+
### Start Parallel Workflow
48+
49+
```bash
50+
cadence --env development \
51+
--domain cadence-samples \
52+
workflow start \
53+
--tl cadence-samples-worker \
54+
--et 60 \
55+
--workflow_type cadence_samples.ParallelWorkflow
56+
```
57+
58+
### What Happens
59+
60+
**BranchWorkflow** - Executes activities in parallel and waits for all:
61+
62+
```
63+
┌─────────────────┐
64+
│ BranchWorkflow │
65+
└────────┬────────┘
66+
67+
┌─────────────┼─────────────┐
68+
▼ ▼ ▼
69+
┌───────┐ ┌───────┐ ┌───────┐
70+
│Branch1│ │Branch2│ │Branch3│
71+
└───┬───┘ └───┬───┘ └───┬───┘
72+
│ │ │
73+
└─────────────┼───────────┘
74+
75+
Wait for all to complete
76+
```
77+
78+
**ParallelWorkflow** - Uses `workflow.Go()` for coroutines:
79+
80+
```
81+
┌──────────────────┐
82+
│ ParallelWorkflow │
83+
└────────┬─────────┘
84+
85+
┌──────────┴──────────┐
86+
▼ ▼
87+
workflow.Go() workflow.Go()
88+
│ │
89+
┌────┴────┐ ┌───┴───┐
90+
▼ ▼ ▼
91+
branch1.1 branch1.2 branch2
92+
│ │ │
93+
└────┬────┘ │
94+
└────────┬────────┘
95+
96+
Wait for both coroutines
97+
```
98+
99+
### Key Concept: Parallel with Futures
100+
101+
```go
102+
var futures []workflow.Future
103+
for i := 1; i <= totalBranches; i++ {
104+
future := workflow.ExecuteActivity(ctx, BranchActivity, input)
105+
futures = append(futures, future)
106+
}
107+
// Wait for all
108+
for _, future := range futures {
109+
future.Get(ctx, nil)
110+
}
111+
```
112+
113+
### Key Concept: Parallel with workflow.Go()
114+
115+
```go
116+
waitChannel := workflow.NewChannel(ctx)
117+
118+
workflow.Go(ctx, func(ctx workflow.Context) {
119+
// Run activities sequentially in this branch
120+
workflow.ExecuteActivity(ctx, activity1).Get(ctx, nil)
121+
workflow.ExecuteActivity(ctx, activity2).Get(ctx, nil)
122+
waitChannel.Send(ctx, "done")
123+
})
124+
125+
workflow.Go(ctx, func(ctx workflow.Context) {
126+
// Run in parallel
127+
workflow.ExecuteActivity(ctx, activity3).Get(ctx, nil)
128+
waitChannel.Send(ctx, "done")
129+
})
130+
131+
// Wait for both coroutines
132+
for i := 0; i < 2; i++ {
133+
waitChannel.Receive(ctx, nil)
134+
}
135+
```
136+
137+
138+
## References
139+
140+
* The website: https://cadenceworkflow.io
141+
* Cadence's server: https://github.com/uber/cadence
142+
* Cadence's Go client: https://github.com/uber-go/cadence-client
143+
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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+
const totalBranches = 3
13+
14+
// BranchWorkflow demonstrates executing multiple activities in parallel using Futures.
15+
// All branches run concurrently and we wait for all to complete.
16+
func BranchWorkflow(ctx workflow.Context) error {
17+
ao := workflow.ActivityOptions{
18+
ScheduleToStartTimeout: time.Minute,
19+
StartToCloseTimeout: time.Minute,
20+
HeartbeatTimeout: time.Second * 20,
21+
}
22+
ctx = workflow.WithActivityOptions(ctx, ao)
23+
24+
logger := workflow.GetLogger(ctx)
25+
logger.Info("BranchWorkflow started")
26+
27+
// Start all activities in parallel
28+
var futures []workflow.Future
29+
for i := 1; i <= totalBranches; i++ {
30+
activityInput := fmt.Sprintf("branch %d of %d", i, totalBranches)
31+
future := workflow.ExecuteActivity(ctx, BranchActivity, activityInput)
32+
futures = append(futures, future)
33+
}
34+
35+
// Wait for all futures to complete
36+
for i, future := range futures {
37+
var result string
38+
if err := future.Get(ctx, &result); err != nil {
39+
logger.Error("Branch failed", zap.Int("branch", i+1), zap.Error(err))
40+
return err
41+
}
42+
logger.Info("Branch completed", zap.Int("branch", i+1), zap.String("result", result))
43+
}
44+
45+
logger.Info("BranchWorkflow completed - all branches finished")
46+
return nil
47+
}
48+
49+
// ParallelWorkflow demonstrates using workflow.Go() to run coroutines in parallel.
50+
// Each coroutine can run multiple sequential activities.
51+
func ParallelWorkflow(ctx workflow.Context) error {
52+
ao := workflow.ActivityOptions{
53+
ScheduleToStartTimeout: time.Minute,
54+
StartToCloseTimeout: time.Minute,
55+
HeartbeatTimeout: time.Second * 20,
56+
}
57+
ctx = workflow.WithActivityOptions(ctx, ao)
58+
59+
logger := workflow.GetLogger(ctx)
60+
logger.Info("ParallelWorkflow started")
61+
62+
waitChannel := workflow.NewChannel(ctx)
63+
64+
// First coroutine: runs two activities sequentially
65+
workflow.Go(ctx, func(ctx workflow.Context) {
66+
err := workflow.ExecuteActivity(ctx, BranchActivity, "branch1.1").Get(ctx, nil)
67+
if err != nil {
68+
logger.Error("Activity failed", zap.Error(err))
69+
waitChannel.Send(ctx, err.Error())
70+
return
71+
}
72+
err = workflow.ExecuteActivity(ctx, BranchActivity, "branch1.2").Get(ctx, nil)
73+
if err != nil {
74+
logger.Error("Activity failed", zap.Error(err))
75+
waitChannel.Send(ctx, err.Error())
76+
return
77+
}
78+
waitChannel.Send(ctx, "")
79+
})
80+
81+
// Second coroutine: runs one activity
82+
workflow.Go(ctx, func(ctx workflow.Context) {
83+
err := workflow.ExecuteActivity(ctx, BranchActivity, "branch2").Get(ctx, nil)
84+
if err != nil {
85+
logger.Error("Activity failed", zap.Error(err))
86+
waitChannel.Send(ctx, err.Error())
87+
return
88+
}
89+
waitChannel.Send(ctx, "")
90+
})
91+
92+
// Wait for both coroutines to complete
93+
var errMsg string
94+
for i := 0; i < 2; i++ {
95+
waitChannel.Receive(ctx, &errMsg)
96+
if errMsg != "" {
97+
err := errors.New(errMsg)
98+
logger.Error("Coroutine failed", zap.Error(err))
99+
return err
100+
}
101+
}
102+
103+
logger.Info("ParallelWorkflow completed")
104+
return nil
105+
}
106+
107+
// BranchActivity is a simple activity that logs and returns a result.
108+
func BranchActivity(input string) (string, error) {
109+
fmt.Printf("BranchActivity running with input: %s\n", input)
110+
return "Result_" + input, nil
111+
}
112+
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: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
## Branch Workflow
2+
3+
This sample demonstrates **parallel activity execution** - running multiple activities concurrently.
4+
5+
### Start Branch 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.BranchWorkflow
14+
```
15+
16+
### Start Parallel Workflow
17+
18+
```bash
19+
cadence --env development \
20+
--domain cadence-samples \
21+
workflow start \
22+
--tl cadence-samples-worker \
23+
--et 60 \
24+
--workflow_type cadence_samples.ParallelWorkflow
25+
```
26+
27+
### What Happens
28+
29+
**BranchWorkflow** - Executes activities in parallel and waits for all:
30+
31+
```
32+
┌─────────────────┐
33+
│ BranchWorkflow │
34+
└────────┬────────┘
35+
36+
┌─────────────┼─────────────┐
37+
▼ ▼ ▼
38+
┌───────┐ ┌───────┐ ┌───────┐
39+
│Branch1│ │Branch2│ │Branch3│
40+
└───┬───┘ └───┬───┘ └───┬───┘
41+
│ │ │
42+
└─────────────┼───────────┘
43+
44+
Wait for all to complete
45+
```
46+
47+
**ParallelWorkflow** - Uses `workflow.Go()` for coroutines:
48+
49+
```
50+
┌──────────────────┐
51+
│ ParallelWorkflow │
52+
└────────┬─────────┘
53+
54+
┌──────────┴──────────┐
55+
▼ ▼
56+
workflow.Go() workflow.Go()
57+
│ │
58+
┌────┴────┐ ┌───┴───┐
59+
▼ ▼ ▼
60+
branch1.1 branch1.2 branch2
61+
│ │ │
62+
└────┬────┘ │
63+
└────────┬────────┘
64+
65+
Wait for both coroutines
66+
```
67+
68+
### Key Concept: Parallel with Futures
69+
70+
```go
71+
var futures []workflow.Future
72+
for i := 1; i <= totalBranches; i++ {
73+
future := workflow.ExecuteActivity(ctx, BranchActivity, input)
74+
futures = append(futures, future)
75+
}
76+
// Wait for all
77+
for _, future := range futures {
78+
future.Get(ctx, nil)
79+
}
80+
```
81+
82+
### Key Concept: Parallel with workflow.Go()
83+
84+
```go
85+
waitChannel := workflow.NewChannel(ctx)
86+
87+
workflow.Go(ctx, func(ctx workflow.Context) {
88+
// Run activities sequentially in this branch
89+
workflow.ExecuteActivity(ctx, activity1).Get(ctx, nil)
90+
workflow.ExecuteActivity(ctx, activity2).Get(ctx, nil)
91+
waitChannel.Send(ctx, "done")
92+
})
93+
94+
workflow.Go(ctx, func(ctx workflow.Context) {
95+
// Run in parallel
96+
workflow.ExecuteActivity(ctx, activity3).Get(ctx, nil)
97+
waitChannel.Send(ctx, "done")
98+
})
99+
100+
// Wait for both coroutines
101+
for i := 0; i < 2; i++ {
102+
waitChannel.Receive(ctx, nil)
103+
}
104+
```
105+

0 commit comments

Comments
 (0)