Skip to content
Merged
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
102 changes: 102 additions & 0 deletions new_samples/hello_world/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!-- THIS IS A GENERATED FILE -->
<!-- PLEASE DO NOT EDIT -->

# Hello World 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

### Start your workflow

This workflow takes an input message and greet you as response. Try the following CLI

```bash
cadence --env development \
--domain cadence-samples \
workflow start \
--workflow_type cadence_samples.HelloWorldWorkflow \
--tl cadence-samples-worker \
--et 60 \
--input '{"message":"Cadence"}'
```

Here are the details to this command:

* `--domain` option describes under which domain to run this workflow
* `--env development` calls the "local" cadence server
* `--workflow_type` option describes which workflow to execute
* `-tl` (or `--tasklist`) tells cadence-server which tasklist to schedule tasks with. This is the same tasklist the worker polls tasks from. See worker.go
* `--et` (or `--execution_timeout`) tells cadence server how long to wait until timing out the workflow
* `--input` is the input to your workflow

To see more options run `cadence --help`

### View your workflow

#### Cadence UI (cadence-web)

Click on `cadence-samples` domain in cadence-web to view your workflow.

* In Summary tab, you will see the input and output to your workflow
* Click on History tab to see individual steps.

#### CLI

List workflows using the following command:

```bash
cadence --env development --domain cadence-samples --workflow list
```

You can view an individual workflow by using the following command:

```bash
cadence --env development \
--domain cadence-samples \
--workflow describe \
--wid <workflow_id>
```

* `workflow` is the noun to run commands within workflow scope
* `describe` is the verb to return the summary of the workflow
* `--wid` (or `--workflow_id`) is the option to pass the workflow id. If there are multiple "run"s, it will return the latest one.
* (optional) `--rid` (or `--run_id`) is the option to pass the run id to describe a specific run, instead of the latest.

To view the entire history of the workflow, use the following command:

```bash
cadence --env development \
--domain cadence-samples \
--workflow show \
--wid <workflow_id>
```

## 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

23 changes: 23 additions & 0 deletions new_samples/hello_world/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.
64 changes: 64 additions & 0 deletions new_samples/hello_world/generator/README_specific.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
### Start your workflow

This workflow takes an input message and greet you as response. Try the following CLI

```bash
cadence --env development \
--domain cadence-samples \
workflow start \
--workflow_type cadence_samples.HelloWorldWorkflow \
--tl cadence-samples-worker \
--et 60 \
--input '{"message":"Cadence"}'
```

Here are the details to this command:

* `--domain` option describes under which domain to run this workflow
* `--env development` calls the "local" cadence server
* `--workflow_type` option describes which workflow to execute
* `-tl` (or `--tasklist`) tells cadence-server which tasklist to schedule tasks with. This is the same tasklist the worker polls tasks from. See worker.go
* `--et` (or `--execution_timeout`) tells cadence server how long to wait until timing out the workflow
* `--input` is the input to your workflow

To see more options run `cadence --help`

### View your workflow

#### Cadence UI (cadence-web)

Click on `cadence-samples` domain in cadence-web to view your workflow.

* In Summary tab, you will see the input and output to your workflow
* Click on History tab to see individual steps.

#### CLI

List workflows using the following command:

```bash
cadence --env development --domain cadence-samples --workflow list
```

You can view an individual workflow by using the following command:

```bash
cadence --env development \
--domain cadence-samples \
--workflow describe \
--wid <workflow_id>
```

* `workflow` is the noun to run commands within workflow scope
* `describe` is the verb to return the summary of the workflow
* `--wid` (or `--workflow_id`) is the option to pass the workflow id. If there are multiple "run"s, it will return the latest one.
* (optional) `--rid` (or `--run_id`) is the option to pass the run id to describe a specific run, instead of the latest.

To view the entire history of the workflow, use the following command:

```bash
cadence --env development \
--domain cadence-samples \
--workflow show \
--wid <workflow_id>
```
16 changes: 16 additions & 0 deletions new_samples/hello_world/generator/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

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

func main() {
// Define the data for HelloWorld
data := template.TemplateData{
SampleName: "Hello World",
Workflows: []string{"HelloWorldWorkflow"},
Activities: []string{"HelloWorldActivity"},
}

template.GenerateAll(data)
}

// Implement custom generator below
20 changes: 20 additions & 0 deletions new_samples/hello_world/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
}
101 changes: 101 additions & 0 deletions new_samples/hello_world/worker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// THIS IS A GENERATED FILE
// PLEASE DO NOT EDIT

// Package worker implements a Cadence worker with basic configurations.
package main

import (
"github.com/uber-go/tally"
apiv1 "github.com/uber/cadence-idl/go/proto/api/v1"
"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
"go.uber.org/cadence/activity"
"go.uber.org/cadence/compatibility"
"go.uber.org/cadence/worker"
"go.uber.org/cadence/workflow"
"go.uber.org/yarpc"
"go.uber.org/yarpc/peer"
yarpchostport "go.uber.org/yarpc/peer/hostport"
"go.uber.org/yarpc/transport/grpc"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

const (
HostPort = "127.0.0.1:7833"
Domain = "cadence-samples"
// TaskListName identifies set of client workflows, activities, and workers.
// It could be your group or client or application name.
TaskListName = "cadence-samples-worker"
ClientName = "cadence-samples-worker"
CadenceService = "cadence-frontend"
)

// StartWorker creates and starts a basic Cadence worker.
func StartWorker() {
logger, cadenceClient := BuildLogger(), BuildCadenceClient()
workerOptions := worker.Options{
Logger: logger,
MetricsScope: tally.NewTestScope(TaskListName, nil),
}

w := worker.New(
cadenceClient,
Domain,
TaskListName,
workerOptions)
// HelloWorld workflow registration
w.RegisterWorkflowWithOptions(HelloWorldWorkflow, workflow.RegisterOptions{Name: "cadence_samples.HelloWorldWorkflow"})
w.RegisterActivityWithOptions(HelloWorldActivity, activity.RegisterOptions{Name: "cadence_samples.HelloWorldActivity"})

err := w.Start()
if err != nil {
panic("Failed to start worker: " + err.Error())
}
logger.Info("Started Worker.", zap.String("worker", TaskListName))

}

func BuildCadenceClient(dialOptions ...grpc.DialOption) workflowserviceclient.Interface {
grpcTransport := grpc.NewTransport()
// Create a single peer chooser that identifies the host/port and configures
// a gRPC dialer with TLS credentials
myChooser := peer.NewSingle(
yarpchostport.Identify(HostPort),
grpcTransport.NewDialer(dialOptions...),
)
outbound := grpcTransport.NewOutbound(myChooser)

dispatcher := yarpc.NewDispatcher(yarpc.Config{
Name: ClientName,
Outbounds: yarpc.Outbounds{
CadenceService: {Unary: outbound},
},
})
if err := dispatcher.Start(); err != nil {
panic("Failed to start dispatcher: " + err.Error())
}

clientConfig := dispatcher.ClientConfig(CadenceService)

// Create a compatibility adapter that wraps proto-based YARPC clients
// to provide a unified interface for domain, workflow, worker, and visibility APIs
return compatibility.NewThrift2ProtoAdapter(
apiv1.NewDomainAPIYARPCClient(clientConfig),
apiv1.NewWorkflowAPIYARPCClient(clientConfig),
apiv1.NewWorkerAPIYARPCClient(clientConfig),
apiv1.NewVisibilityAPIYARPCClient(clientConfig),
)
}

func BuildLogger() *zap.Logger {
config := zap.NewDevelopmentConfig()
config.Level.SetLevel(zapcore.InfoLevel)

var err error
logger, err := config.Build()
if err != nil {
panic("Failed to setup logger: " + err.Error())
}

return logger
}
45 changes: 45 additions & 0 deletions new_samples/hello_world/workflow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package main

import (
"context"
"fmt"
"go.uber.org/cadence/activity"
"go.uber.org/cadence/workflow"
"go.uber.org/zap"
"time"
)

type sampleInput struct {
Message string `json:"message"`
}

// This is the workflow function
// Given an input, HelloWorldWorkflow returns "Hello <input>!"
func HelloWorldWorkflow(ctx workflow.Context, input sampleInput) (string, error) {
ao := workflow.ActivityOptions{
ScheduleToStartTimeout: time.Minute,
StartToCloseTimeout: time.Minute,
}
ctx = workflow.WithActivityOptions(ctx, ao)

logger := workflow.GetLogger(ctx)
logger.Info("HelloWorldWorkflow started")

var greetingMsg string
err := workflow.ExecuteActivity(ctx, HelloWorldActivity, input).Get(ctx, &greetingMsg)
if err != nil {
logger.Error("HelloWorldActivity failed", zap.Error(err))
return "", err
}

logger.Info("Workflow result", zap.String("greeting", greetingMsg))
return greetingMsg, nil
}

// This is the activity function
// Given an input, HelloWorldActivity returns "Hello <input>!"
func HelloWorldActivity(ctx context.Context, input sampleInput) (string, error) {
logger := activity.GetLogger(ctx)
logger.Info("HelloWorldActivity started")
return fmt.Sprintf("Hello, %s!", input.Message), nil
}
Loading
Loading