Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions new_samples/childworkflow/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<!-- THIS IS A GENERATED FILE -->
<!-- PLEASE DO NOT EDIT -->

# Child Workflow Sample

## Prerequisites

0. Install Cadence CLI. See instruction [here](https://cadenceworkflow.io/docs/cli/).
1. Run the Cadence server:
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`
2. Run `docker compose -f docker/docker-compose.yml up` to start Cadence server
3. See more details at https://github.com/uber/cadence/blob/master/README.md
2. Once everything is up and running in Docker, open [localhost:8088](localhost:8088) to view Cadence UI.
3. Register the `cadence-samples` domain:

```bash
cadence --env development --domain cadence-samples domain register
```

Refresh the [domains page](http://localhost:8088/domains) from step 2 to verify `cadence-samples` is registered.

## Steps to run sample

Inside the folder this sample is defined, run the following command:

```bash
go run .
```

This will call the main function in main.go which starts the worker, which will be execute the sample workflow code

## Child Workflow Sample

This sample demonstrates **parent-child workflow relationships** and the **ContinueAsNew** pattern.

### Start the Workflow

```bash
cadence --env development \
--domain cadence-samples \
workflow start \
--tl cadence-samples-worker \
--et 60 \
--workflow_type cadence_samples.ParentWorkflow
```

### What Happens

```
┌─────────────────────┐
│ ParentWorkflow │
└──────────┬──────────┘
│ ExecuteChildWorkflow
┌─────────────────────┐
│ ChildWorkflow │──┐
│ (run 1 of 5) │ │
└─────────────────────┘ │
│ │ ContinueAsNew
▼ │
┌─────────────────────┐ │
│ ChildWorkflow │──┤
│ (run 2 of 5) │ │
└─────────────────────┘ │
│ │
... ...
│ │
▼ │
┌─────────────────────┐ │
│ ChildWorkflow │◀─┘
│ (run 5 of 5) │
└─────────────────────┘
│ Returns result
┌─────────────────────┐
│ ParentWorkflow │
│ completes │
└─────────────────────┘
```

1. Parent workflow starts a child workflow
2. Child workflow uses `ContinueAsNew` to restart itself 5 times
3. After 5 runs, child completes and returns result to parent

### Key Concept: Child Workflow Options

```go
cwo := workflow.ChildWorkflowOptions{
WorkflowID: childID,
ExecutionStartToCloseTimeout: time.Minute,
}
ctx = workflow.WithChildOptions(ctx, cwo)

err := workflow.ExecuteChildWorkflow(ctx, ChildWorkflow, args...).Get(ctx, &result)
```

### Key Concept: ContinueAsNew

```go
// Instead of recursion (which grows history), use ContinueAsNew
return "", workflow.NewContinueAsNewError(ctx, ChildWorkflow, newArgs...)
```

ContinueAsNew starts a new workflow run with fresh history, avoiding unbounded history growth.


## References

* The website: https://cadenceworkflow.io
* Cadence's server: https://github.com/uber/cadence
* Cadence's Go client: https://github.com/uber-go/cadence-client

64 changes: 64 additions & 0 deletions new_samples/childworkflow/childworkflow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package main

import (
"errors"
"fmt"
"time"

"go.uber.org/cadence/workflow"
"go.uber.org/zap"
)

// ParentWorkflow demonstrates invoking a child workflow from a parent.
// The parent waits for the child to complete before finishing.
func ParentWorkflow(ctx workflow.Context) error {
logger := workflow.GetLogger(ctx)
logger.Info("ParentWorkflow started")

execution := workflow.GetInfo(ctx).WorkflowExecution
// Parent can specify its own ID for child execution
childID := fmt.Sprintf("child_workflow:%v", execution.RunID)

cwo := workflow.ChildWorkflowOptions{
WorkflowID: childID,
ExecutionStartToCloseTimeout: time.Minute,
}
ctx = workflow.WithChildOptions(ctx, cwo)

// Execute child workflow and wait for result
var result string
err := workflow.ExecuteChildWorkflow(ctx, ChildWorkflow, 0, 5).Get(ctx, &result)
if err != nil {
logger.Error("Child workflow failed", zap.Error(err))
return err
}

logger.Info("ParentWorkflow completed", zap.String("result", result))
return nil
}

// ChildWorkflow demonstrates ContinueAsNew pattern.
// It runs multiple times, restarting itself with ContinueAsNew until runCount reaches 0.
func ChildWorkflow(ctx workflow.Context, totalCount, runCount int) (string, error) {
logger := workflow.GetLogger(ctx)
logger.Info("ChildWorkflow started", zap.Int("totalCount", totalCount), zap.Int("runCount", runCount))

if runCount <= 0 {
logger.Error("Invalid run count", zap.Int("runCount", runCount))
return "", errors.New("invalid run count")
}

totalCount++
runCount--

if runCount == 0 {
result := fmt.Sprintf("Child workflow completed after %d runs", totalCount)
logger.Info("ChildWorkflow completed", zap.String("result", result))
return result, nil
}

// ContinueAsNew: start a new run with fresh history
logger.Info("ChildWorkflow continuing as new", zap.Int("remainingRuns", runCount))
return "", workflow.NewContinueAsNewError(ctx, ChildWorkflow, totalCount, runCount)
}

23 changes: 23 additions & 0 deletions new_samples/childworkflow/generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- THIS IS A GENERATED FILE -->
<!-- PLEASE DO NOT EDIT -->

# Sample Generator

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.

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:

* Cadence client initialization
* Worker with workflow and activity registrations
* Workflow starter
* and the workflow code itself

Some samples may have more or fewer parts depending on what they need to demonstrate.

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.

## Contributing

* When creating a new sample, follow the steps mentioned in the README file in the main samples folder.
* To update the sample workflow code, edit the workflow file directly.
* 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.
76 changes: 76 additions & 0 deletions new_samples/childworkflow/generator/README_specific.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
## Child Workflow Sample

This sample demonstrates **parent-child workflow relationships** and the **ContinueAsNew** pattern.

### Start the Workflow

```bash
cadence --env development \
--domain cadence-samples \
workflow start \
--tl cadence-samples-worker \
--et 60 \
--workflow_type cadence_samples.ParentWorkflow
```

### What Happens

```
┌─────────────────────┐
│ ParentWorkflow │
└──────────┬──────────┘
│ ExecuteChildWorkflow
┌─────────────────────┐
│ ChildWorkflow │──┐
│ (run 1 of 5) │ │
└─────────────────────┘ │
│ │ ContinueAsNew
▼ │
┌─────────────────────┐ │
│ ChildWorkflow │──┤
│ (run 2 of 5) │ │
└─────────────────────┘ │
│ │
... ...
│ │
▼ │
┌─────────────────────┐ │
│ ChildWorkflow │◀─┘
│ (run 5 of 5) │
└─────────────────────┘
│ Returns result
┌─────────────────────┐
│ ParentWorkflow │
│ completes │
└─────────────────────┘
```

1. Parent workflow starts a child workflow
2. Child workflow uses `ContinueAsNew` to restart itself 5 times
3. After 5 runs, child completes and returns result to parent

### Key Concept: Child Workflow Options

```go
cwo := workflow.ChildWorkflowOptions{
WorkflowID: childID,
ExecutionStartToCloseTimeout: time.Minute,
}
ctx = workflow.WithChildOptions(ctx, cwo)

err := workflow.ExecuteChildWorkflow(ctx, ChildWorkflow, args...).Get(ctx, &result)
```

### Key Concept: ContinueAsNew

```go
// Instead of recursion (which grows history), use ContinueAsNew
return "", workflow.NewContinueAsNewError(ctx, ChildWorkflow, newArgs...)
```

ContinueAsNew starts a new workflow run with fresh history, avoiding unbounded history growth.

14 changes: 14 additions & 0 deletions new_samples/childworkflow/generator/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "github.com/uber-common/cadence-samples/new_samples/template"

func main() {
data := template.TemplateData{
SampleName: "Child Workflow",
Workflows: []string{"ParentWorkflow", "ChildWorkflow"},
Activities: []string{},
}

template.GenerateAll(data)
}

20 changes: 20 additions & 0 deletions new_samples/childworkflow/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// THIS IS A GENERATED FILE
// PLEASE DO NOT EDIT

package main

import (
"fmt"
"os"
"os/signal"
"syscall"
)

func main() {
StartWorker()

done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGINT)
fmt.Println("Cadence worker started, press ctrl+c to terminate...")
<-done
}
Loading
Loading