From a636924023eb1f2905eccf0b23f15ceefa1910c8 Mon Sep 17 00:00:00 2001 From: Ender Demirkaya Date: Sun, 23 Nov 2025 20:29:08 -0800 Subject: [PATCH 1/7] Redefine hello world sample Signed-off-by: Ender Demirkaya --- new_samples/hello_world/README.md | 98 +++++++++++++++++++++++++++++ new_samples/hello_world/main.go | 17 +++++ new_samples/hello_world/worker.go | 98 +++++++++++++++++++++++++++++ new_samples/hello_world/workflow.go | 45 +++++++++++++ 4 files changed, 258 insertions(+) create mode 100644 new_samples/hello_world/README.md create mode 100644 new_samples/hello_world/main.go create mode 100644 new_samples/hello_world/worker.go create mode 100644 new_samples/hello_world/workflow.go diff --git a/new_samples/hello_world/README.md b/new_samples/hello_world/README.md new file mode 100644 index 0000000..060c1f7 --- /dev/null +++ b/new_samples/hello_world/README.md @@ -0,0 +1,98 @@ +# Cadence Samples + +These are some samples to demonstrate various capabilities of Cadence client and server. You can learn more about cadence at: + +* The website: https://cadenceworkflow.io +* Cadence's server: https://github.com/uber/cadence +* Cadence's Go client: https://github.com/uber-go/cadence-client + +## Prerequisite + +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` 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 +``` diff --git a/new_samples/hello_world/main.go b/new_samples/hello_world/main.go new file mode 100644 index 0000000..ebddf9b --- /dev/null +++ b/new_samples/hello_world/main.go @@ -0,0 +1,17 @@ +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 +} diff --git a/new_samples/hello_world/worker.go b/new_samples/hello_world/worker.go new file mode 100644 index 0000000..539b3e6 --- /dev/null +++ b/new_samples/hello_world/worker.go @@ -0,0 +1,98 @@ +// 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 +} diff --git a/new_samples/hello_world/workflow.go b/new_samples/hello_world/workflow.go new file mode 100644 index 0000000..3f90d78 --- /dev/null +++ b/new_samples/hello_world/workflow.go @@ -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 !" +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 !" +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 +} From aaacf61b98cc94ab017867474c9e00338cd92d12 Mon Sep 17 00:00:00 2001 From: Ender Demirkaya Date: Sun, 23 Nov 2025 21:30:51 -0800 Subject: [PATCH 2/7] Use templates Signed-off-by: Ender Demirkaya --- new_samples/hello_world_generated/README.md | 98 +++++++++++++++++ .../generator/README_specific.md | 64 +++++++++++ .../generator/generate.go | 84 +++++++++++++++ new_samples/hello_world_generated/main.go | 17 +++ new_samples/hello_world_generated/worker.go | 98 +++++++++++++++++ new_samples/hello_world_generated/workflow.go | 45 ++++++++ new_samples/template/README.tmpl | 34 ++++++ new_samples/template/main.tmpl | 17 +++ new_samples/template/worker.tmpl | 102 ++++++++++++++++++ 9 files changed, 559 insertions(+) create mode 100644 new_samples/hello_world_generated/README.md create mode 100644 new_samples/hello_world_generated/generator/README_specific.md create mode 100644 new_samples/hello_world_generated/generator/generate.go create mode 100644 new_samples/hello_world_generated/main.go create mode 100644 new_samples/hello_world_generated/worker.go create mode 100644 new_samples/hello_world_generated/workflow.go create mode 100644 new_samples/template/README.tmpl create mode 100644 new_samples/template/main.tmpl create mode 100644 new_samples/template/worker.tmpl diff --git a/new_samples/hello_world_generated/README.md b/new_samples/hello_world_generated/README.md new file mode 100644 index 0000000..060c1f7 --- /dev/null +++ b/new_samples/hello_world_generated/README.md @@ -0,0 +1,98 @@ +# Cadence Samples + +These are some samples to demonstrate various capabilities of Cadence client and server. You can learn more about cadence at: + +* The website: https://cadenceworkflow.io +* Cadence's server: https://github.com/uber/cadence +* Cadence's Go client: https://github.com/uber-go/cadence-client + +## Prerequisite + +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` 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 +``` diff --git a/new_samples/hello_world_generated/generator/README_specific.md b/new_samples/hello_world_generated/generator/README_specific.md new file mode 100644 index 0000000..4833782 --- /dev/null +++ b/new_samples/hello_world_generated/generator/README_specific.md @@ -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` 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 +``` diff --git a/new_samples/hello_world_generated/generator/generate.go b/new_samples/hello_world_generated/generator/generate.go new file mode 100644 index 0000000..368e2bf --- /dev/null +++ b/new_samples/hello_world_generated/generator/generate.go @@ -0,0 +1,84 @@ +package main + +import ( + "io" + "os" + "text/template" +) + +type TemplateData struct { + Workflows []string + Activities []string +} + +func main() { + // Define the data for HelloWorld + data := TemplateData{ + Workflows: []string{"HelloWorldWorkflow"}, + Activities: []string{"HelloWorldActivity"}, + } + + // Generate worker.go + generateFile("../../template/worker.tmpl", "../worker.go", data) + println("Generated worker.go") + + // Generate main.go + generateFile("../../template/main.tmpl", "../main.go", data) + println("Generated main.go") + + // Generate README.md (combine template + specific) + generateREADME("../../template/README.tmpl", "README_specific.md", "../README.md", data) + println("Generated README.md") +} + +func generateFile(templatePath, outputPath string, data TemplateData) { + tmpl, err := template.ParseFiles(templatePath) + if err != nil { + panic("Failed to parse template " + templatePath + ": " + err.Error()) + } + + f, err := os.Create(outputPath) + if err != nil { + panic("Failed to create output file " + outputPath + ": " + err.Error()) + } + defer f.Close() + + err = tmpl.Execute(f, data) + if err != nil { + panic("Failed to execute template: " + err.Error()) + } +} + +func generateREADME(templatePath, specificPath, outputPath string, data TemplateData) { + // Create output file + f, err := os.Create(outputPath) + if err != nil { + panic("Failed to create README file: " + err.Error()) + } + defer f.Close() + + // First, write the generic template part + tmpl, err := template.ParseFiles(templatePath) + if err != nil { + panic("Failed to parse README template: " + err.Error()) + } + + err = tmpl.Execute(f, data) + if err != nil { + panic("Failed to execute README template: " + err.Error()) + } + + // Then, append the specific content + specific, err := os.Open(specificPath) + if err != nil { + panic("Failed to open specific README content: " + err.Error()) + } + defer specific.Close() + + _, err = io.Copy(f, specific) + if err != nil { + panic("Failed to append specific README content: " + err.Error()) + } +} + + diff --git a/new_samples/hello_world_generated/main.go b/new_samples/hello_world_generated/main.go new file mode 100644 index 0000000..ebddf9b --- /dev/null +++ b/new_samples/hello_world_generated/main.go @@ -0,0 +1,17 @@ +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 +} diff --git a/new_samples/hello_world_generated/worker.go b/new_samples/hello_world_generated/worker.go new file mode 100644 index 0000000..539b3e6 --- /dev/null +++ b/new_samples/hello_world_generated/worker.go @@ -0,0 +1,98 @@ +// 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 +} diff --git a/new_samples/hello_world_generated/workflow.go b/new_samples/hello_world_generated/workflow.go new file mode 100644 index 0000000..3f90d78 --- /dev/null +++ b/new_samples/hello_world_generated/workflow.go @@ -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 !" +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 !" +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 +} diff --git a/new_samples/template/README.tmpl b/new_samples/template/README.tmpl new file mode 100644 index 0000000..9d0001a --- /dev/null +++ b/new_samples/template/README.tmpl @@ -0,0 +1,34 @@ +# Cadence Samples + +These are some samples to demonstrate various capabilities of Cadence client and server. You can learn more about cadence at: + +* The website: https://cadenceworkflow.io +* Cadence's server: https://github.com/uber/cadence +* Cadence's Go client: https://github.com/uber-go/cadence-client + +## Prerequisite + +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 + diff --git a/new_samples/template/main.tmpl b/new_samples/template/main.tmpl new file mode 100644 index 0000000..ebddf9b --- /dev/null +++ b/new_samples/template/main.tmpl @@ -0,0 +1,17 @@ +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 +} diff --git a/new_samples/template/worker.tmpl b/new_samples/template/worker.tmpl new file mode 100644 index 0000000..4e022ea --- /dev/null +++ b/new_samples/template/worker.tmpl @@ -0,0 +1,102 @@ +// 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 + {{- range .Workflows}} + w.RegisterWorkflowWithOptions({{.}}, workflow.RegisterOptions{Name: "cadence_samples.{{.}}"}) + {{- end}} + {{- range .Activities}} + w.RegisterActivityWithOptions({{.}}, activity.RegisterOptions{Name: "cadence_samples.{{.}}"}) + {{- end}} + + 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 +} From 5e88cc2c2da4191ae5c37405bb3eee967bc92e4e Mon Sep 17 00:00:00 2001 From: Ender Demirkaya Date: Sun, 23 Nov 2025 21:46:08 -0800 Subject: [PATCH 3/7] Introduce the new structure Signed-off-by: Ender Demirkaya --- .../hello_world/generator/README_specific.md | 64 ++++++++++++ new_samples/hello_world/generator/generate.go | 98 +++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 new_samples/hello_world/generator/README_specific.md create mode 100644 new_samples/hello_world/generator/generate.go diff --git a/new_samples/hello_world/generator/README_specific.md b/new_samples/hello_world/generator/README_specific.md new file mode 100644 index 0000000..4833782 --- /dev/null +++ b/new_samples/hello_world/generator/README_specific.md @@ -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` 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 +``` diff --git a/new_samples/hello_world/generator/generate.go b/new_samples/hello_world/generator/generate.go new file mode 100644 index 0000000..a389408 --- /dev/null +++ b/new_samples/hello_world/generator/generate.go @@ -0,0 +1,98 @@ +package main + +import ( + "io" + "os" + "text/template" +) + +type TemplateData struct { + SampleName string + Workflows []string + Activities []string +} + +func main() { + // Define the data for HelloWorld + data := TemplateData{ + SampleName: "Hello World", + Workflows: []string{"HelloWorldWorkflow"}, + Activities: []string{"HelloWorldActivity"}, + } + + // Generate worker.go + generateFile("../../template/worker.tmpl", "../worker.go", data) + println("Generated worker.go") + + // Generate main.go + generateFile("../../template/main.tmpl", "../main.go", data) + println("Generated main.go") + + // Generate README.md (combine template + specific + references) + generateREADME("../../template/README.tmpl", "README_specific.md", "../../template/README_references.md", "../README.md", data) + println("Generated README.md") +} + +func generateFile(templatePath, outputPath string, data TemplateData) { + tmpl, err := template.ParseFiles(templatePath) + if err != nil { + panic("Failed to parse template " + templatePath + ": " + err.Error()) + } + + f, err := os.Create(outputPath) + if err != nil { + panic("Failed to create output file " + outputPath + ": " + err.Error()) + } + defer f.Close() + + err = tmpl.Execute(f, data) + if err != nil { + panic("Failed to execute template: " + err.Error()) + } +} + +func generateREADME(templatePath, specificPath, referencesPath, outputPath string, data TemplateData) { + // Create output file + f, err := os.Create(outputPath) + if err != nil { + panic("Failed to create README file: " + err.Error()) + } + defer f.Close() + + // First, write the generic template part + tmpl, err := template.ParseFiles(templatePath) + if err != nil { + panic("Failed to parse README template: " + err.Error()) + } + + err = tmpl.Execute(f, data) + if err != nil { + panic("Failed to execute README template: " + err.Error()) + } + + // Then, append the specific content + specific, err := os.Open(specificPath) + if err != nil { + panic("Failed to open specific README content: " + err.Error()) + } + defer specific.Close() + + _, err = io.Copy(f, specific) + if err != nil { + panic("Failed to append specific README content: " + err.Error()) + } + + // Finally, append the references + references, err := os.Open(referencesPath) + if err != nil { + panic("Failed to open references content: " + err.Error()) + } + defer references.Close() + + _, err = io.Copy(f, references) + if err != nil { + panic("Failed to append references content: " + err.Error()) + } +} + + From b9abeed0810791b3e4da322d3504f32012204b92 Mon Sep 17 00:00:00 2001 From: Ender Demirkaya Date: Sun, 23 Nov 2025 21:46:33 -0800 Subject: [PATCH 4/7] Introduce the new structure Signed-off-by: Ender Demirkaya --- new_samples/hello_world/README.md | 18 ++-- new_samples/hello_world/main.go | 3 + new_samples/hello_world/worker.go | 3 + new_samples/hello_world_generated/README.md | 98 ------------------- .../generator/README_specific.md | 64 ------------ .../generator/generate.go | 84 ---------------- new_samples/hello_world_generated/main.go | 17 ---- new_samples/hello_world_generated/worker.go | 98 ------------------- new_samples/hello_world_generated/workflow.go | 45 --------- new_samples/template/README.tmpl | 11 +-- new_samples/template/README_references.md | 7 ++ new_samples/template/main.tmpl | 3 + new_samples/template/worker.tmpl | 3 + 13 files changed, 34 insertions(+), 420 deletions(-) delete mode 100644 new_samples/hello_world_generated/README.md delete mode 100644 new_samples/hello_world_generated/generator/README_specific.md delete mode 100644 new_samples/hello_world_generated/generator/generate.go delete mode 100644 new_samples/hello_world_generated/main.go delete mode 100644 new_samples/hello_world_generated/worker.go delete mode 100644 new_samples/hello_world_generated/workflow.go create mode 100644 new_samples/template/README_references.md diff --git a/new_samples/hello_world/README.md b/new_samples/hello_world/README.md index 060c1f7..b466931 100644 --- a/new_samples/hello_world/README.md +++ b/new_samples/hello_world/README.md @@ -1,12 +1,9 @@ -# Cadence Samples + + -These are some samples to demonstrate various capabilities of Cadence client and server. You can learn more about cadence at: +# Hello World Sample -* The website: https://cadenceworkflow.io -* Cadence's server: https://github.com/uber/cadence -* Cadence's Go client: https://github.com/uber-go/cadence-client - -## Prerequisite +## Prerequisites 0. Install Cadence CLI. See instruction [here](https://cadenceworkflow.io/docs/cli/). 1. Run the Cadence server: @@ -96,3 +93,10 @@ cadence --env development \ --workflow show \ --wid ``` + +## 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 + diff --git a/new_samples/hello_world/main.go b/new_samples/hello_world/main.go index ebddf9b..5893999 100644 --- a/new_samples/hello_world/main.go +++ b/new_samples/hello_world/main.go @@ -1,3 +1,6 @@ +// THIS IS A GENERATED FILE +// PLEASE DO NOT EDIT + package main import ( diff --git a/new_samples/hello_world/worker.go b/new_samples/hello_world/worker.go index 539b3e6..c81932c 100644 --- a/new_samples/hello_world/worker.go +++ b/new_samples/hello_world/worker.go @@ -1,3 +1,6 @@ +// THIS IS A GENERATED FILE +// PLEASE DO NOT EDIT + // Package worker implements a Cadence worker with basic configurations. package main diff --git a/new_samples/hello_world_generated/README.md b/new_samples/hello_world_generated/README.md deleted file mode 100644 index 060c1f7..0000000 --- a/new_samples/hello_world_generated/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# Cadence Samples - -These are some samples to demonstrate various capabilities of Cadence client and server. You can learn more about cadence at: - -* The website: https://cadenceworkflow.io -* Cadence's server: https://github.com/uber/cadence -* Cadence's Go client: https://github.com/uber-go/cadence-client - -## Prerequisite - -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` 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 -``` diff --git a/new_samples/hello_world_generated/generator/README_specific.md b/new_samples/hello_world_generated/generator/README_specific.md deleted file mode 100644 index 4833782..0000000 --- a/new_samples/hello_world_generated/generator/README_specific.md +++ /dev/null @@ -1,64 +0,0 @@ -### 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` 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 -``` diff --git a/new_samples/hello_world_generated/generator/generate.go b/new_samples/hello_world_generated/generator/generate.go deleted file mode 100644 index 368e2bf..0000000 --- a/new_samples/hello_world_generated/generator/generate.go +++ /dev/null @@ -1,84 +0,0 @@ -package main - -import ( - "io" - "os" - "text/template" -) - -type TemplateData struct { - Workflows []string - Activities []string -} - -func main() { - // Define the data for HelloWorld - data := TemplateData{ - Workflows: []string{"HelloWorldWorkflow"}, - Activities: []string{"HelloWorldActivity"}, - } - - // Generate worker.go - generateFile("../../template/worker.tmpl", "../worker.go", data) - println("Generated worker.go") - - // Generate main.go - generateFile("../../template/main.tmpl", "../main.go", data) - println("Generated main.go") - - // Generate README.md (combine template + specific) - generateREADME("../../template/README.tmpl", "README_specific.md", "../README.md", data) - println("Generated README.md") -} - -func generateFile(templatePath, outputPath string, data TemplateData) { - tmpl, err := template.ParseFiles(templatePath) - if err != nil { - panic("Failed to parse template " + templatePath + ": " + err.Error()) - } - - f, err := os.Create(outputPath) - if err != nil { - panic("Failed to create output file " + outputPath + ": " + err.Error()) - } - defer f.Close() - - err = tmpl.Execute(f, data) - if err != nil { - panic("Failed to execute template: " + err.Error()) - } -} - -func generateREADME(templatePath, specificPath, outputPath string, data TemplateData) { - // Create output file - f, err := os.Create(outputPath) - if err != nil { - panic("Failed to create README file: " + err.Error()) - } - defer f.Close() - - // First, write the generic template part - tmpl, err := template.ParseFiles(templatePath) - if err != nil { - panic("Failed to parse README template: " + err.Error()) - } - - err = tmpl.Execute(f, data) - if err != nil { - panic("Failed to execute README template: " + err.Error()) - } - - // Then, append the specific content - specific, err := os.Open(specificPath) - if err != nil { - panic("Failed to open specific README content: " + err.Error()) - } - defer specific.Close() - - _, err = io.Copy(f, specific) - if err != nil { - panic("Failed to append specific README content: " + err.Error()) - } -} - - diff --git a/new_samples/hello_world_generated/main.go b/new_samples/hello_world_generated/main.go deleted file mode 100644 index ebddf9b..0000000 --- a/new_samples/hello_world_generated/main.go +++ /dev/null @@ -1,17 +0,0 @@ -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 -} diff --git a/new_samples/hello_world_generated/worker.go b/new_samples/hello_world_generated/worker.go deleted file mode 100644 index 539b3e6..0000000 --- a/new_samples/hello_world_generated/worker.go +++ /dev/null @@ -1,98 +0,0 @@ -// 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 -} diff --git a/new_samples/hello_world_generated/workflow.go b/new_samples/hello_world_generated/workflow.go deleted file mode 100644 index 3f90d78..0000000 --- a/new_samples/hello_world_generated/workflow.go +++ /dev/null @@ -1,45 +0,0 @@ -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 !" -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 !" -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 -} diff --git a/new_samples/template/README.tmpl b/new_samples/template/README.tmpl index 9d0001a..a291806 100644 --- a/new_samples/template/README.tmpl +++ b/new_samples/template/README.tmpl @@ -1,12 +1,9 @@ -# Cadence Samples + + -These are some samples to demonstrate various capabilities of Cadence client and server. You can learn more about cadence at: +# {{.SampleName}} Sample -* The website: https://cadenceworkflow.io -* Cadence's server: https://github.com/uber/cadence -* Cadence's Go client: https://github.com/uber-go/cadence-client - -## Prerequisite +## Prerequisites 0. Install Cadence CLI. See instruction [here](https://cadenceworkflow.io/docs/cli/). 1. Run the Cadence server: diff --git a/new_samples/template/README_references.md b/new_samples/template/README_references.md new file mode 100644 index 0000000..8044aff --- /dev/null +++ b/new_samples/template/README_references.md @@ -0,0 +1,7 @@ + +## 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 + diff --git a/new_samples/template/main.tmpl b/new_samples/template/main.tmpl index ebddf9b..5893999 100644 --- a/new_samples/template/main.tmpl +++ b/new_samples/template/main.tmpl @@ -1,3 +1,6 @@ +// THIS IS A GENERATED FILE +// PLEASE DO NOT EDIT + package main import ( diff --git a/new_samples/template/worker.tmpl b/new_samples/template/worker.tmpl index 4e022ea..aa9ab90 100644 --- a/new_samples/template/worker.tmpl +++ b/new_samples/template/worker.tmpl @@ -1,3 +1,6 @@ +// THIS IS A GENERATED FILE +// PLEASE DO NOT EDIT + // Package worker implements a Cadence worker with basic configurations. package main From bb211916d6e3ff63673c34098b6e6cd2e420d0f8 Mon Sep 17 00:00:00 2001 From: Ender Demirkaya Date: Mon, 24 Nov 2025 12:33:01 -0800 Subject: [PATCH 5/7] Add more documentation + refactor Signed-off-by: Ender Demirkaya --- new_samples/hello_world/generator/README.md | 23 +++++ new_samples/hello_world/generator/generate.go | 90 +------------------ new_samples/template/README_generator.tmpl | 23 +++++ ...E_references.md => README_references.tmpl} | 0 new_samples/template/generator.go | 79 ++++++++++++++++ 5 files changed, 129 insertions(+), 86 deletions(-) create mode 100644 new_samples/hello_world/generator/README.md create mode 100644 new_samples/template/README_generator.tmpl rename new_samples/template/{README_references.md => README_references.tmpl} (100%) create mode 100644 new_samples/template/generator.go diff --git a/new_samples/hello_world/generator/README.md b/new_samples/hello_world/generator/README.md new file mode 100644 index 0000000..1da3502 --- /dev/null +++ b/new_samples/hello_world/generator/README.md @@ -0,0 +1,23 @@ + + + +# 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. diff --git a/new_samples/hello_world/generator/generate.go b/new_samples/hello_world/generator/generate.go index a389408..0667645 100644 --- a/new_samples/hello_world/generator/generate.go +++ b/new_samples/hello_world/generator/generate.go @@ -1,98 +1,16 @@ package main -import ( - "io" - "os" - "text/template" -) - -type TemplateData struct { - SampleName string - Workflows []string - Activities []string -} +import "github.com/uber-common/cadence-samples/new_samples/template" func main() { // Define the data for HelloWorld - data := TemplateData{ + data := template.TemplateData{ SampleName: "Hello World", Workflows: []string{"HelloWorldWorkflow"}, Activities: []string{"HelloWorldActivity"}, } - // Generate worker.go - generateFile("../../template/worker.tmpl", "../worker.go", data) - println("Generated worker.go") - - // Generate main.go - generateFile("../../template/main.tmpl", "../main.go", data) - println("Generated main.go") - - // Generate README.md (combine template + specific + references) - generateREADME("../../template/README.tmpl", "README_specific.md", "../../template/README_references.md", "../README.md", data) - println("Generated README.md") -} - -func generateFile(templatePath, outputPath string, data TemplateData) { - tmpl, err := template.ParseFiles(templatePath) - if err != nil { - panic("Failed to parse template " + templatePath + ": " + err.Error()) - } - - f, err := os.Create(outputPath) - if err != nil { - panic("Failed to create output file " + outputPath + ": " + err.Error()) - } - defer f.Close() - - err = tmpl.Execute(f, data) - if err != nil { - panic("Failed to execute template: " + err.Error()) - } + template.GenerateAll(data) } -func generateREADME(templatePath, specificPath, referencesPath, outputPath string, data TemplateData) { - // Create output file - f, err := os.Create(outputPath) - if err != nil { - panic("Failed to create README file: " + err.Error()) - } - defer f.Close() - - // First, write the generic template part - tmpl, err := template.ParseFiles(templatePath) - if err != nil { - panic("Failed to parse README template: " + err.Error()) - } - - err = tmpl.Execute(f, data) - if err != nil { - panic("Failed to execute README template: " + err.Error()) - } - - // Then, append the specific content - specific, err := os.Open(specificPath) - if err != nil { - panic("Failed to open specific README content: " + err.Error()) - } - defer specific.Close() - - _, err = io.Copy(f, specific) - if err != nil { - panic("Failed to append specific README content: " + err.Error()) - } - - // Finally, append the references - references, err := os.Open(referencesPath) - if err != nil { - panic("Failed to open references content: " + err.Error()) - } - defer references.Close() - - _, err = io.Copy(f, references) - if err != nil { - panic("Failed to append references content: " + err.Error()) - } -} - - +// Implement custom generator below \ No newline at end of file diff --git a/new_samples/template/README_generator.tmpl b/new_samples/template/README_generator.tmpl new file mode 100644 index 0000000..1da3502 --- /dev/null +++ b/new_samples/template/README_generator.tmpl @@ -0,0 +1,23 @@ + + + +# 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. diff --git a/new_samples/template/README_references.md b/new_samples/template/README_references.tmpl similarity index 100% rename from new_samples/template/README_references.md rename to new_samples/template/README_references.tmpl diff --git a/new_samples/template/generator.go b/new_samples/template/generator.go new file mode 100644 index 0000000..ce8a7f5 --- /dev/null +++ b/new_samples/template/generator.go @@ -0,0 +1,79 @@ +package template + +import ( + "os" + "text/template" +) + +type TemplateData struct { + SampleName string + Workflows []string + Activities []string +} + +func GenerateAll(data TemplateData) { + GenerateWorker(data) + GenerateMain(data) + GenerateSampleReadMe(data) + GenerateGeneratorReadMe(data) +} + +func GenerateWorker(data TemplateData) { + GenerateFile("../../template/worker.tmpl", "../worker.go", data) + println("Generated worker.go") +} + +func GenerateMain(data TemplateData) { + GenerateFile("../../template/main.tmpl", "../main.go", data) + println("Generated main.go") +} + +func GenerateSampleReadMe(data TemplateData) { + inputs := []string{"../../template/README.tmpl", "README_specific.md", "../../template/README_references.tmpl"} + GenerateREADME(inputs, "../README.md", data) +} + +func GenerateGeneratorReadMe(data TemplateData) { + GenerateFile("../../template/README_generator.tmpl", "README.md", data) + println("Generated README.md") +} + +func GenerateFile(templatePath, outputPath string, data TemplateData) { + tmpl, err := template.ParseFiles(templatePath) + if err != nil { + panic("Failed to parse template " + templatePath + ": " + err.Error()) + } + + f, err := os.Create(outputPath) + if err != nil { + panic("Failed to create output file " + outputPath + ": " + err.Error()) + } + defer f.Close() + + err = tmpl.Execute(f, data) + if err != nil { + panic("Failed to execute template: " + err.Error()) + } +} + +func GenerateREADME(inputs []string, outputPath string, data TemplateData) { + // Create output file + f, err := os.Create(outputPath) + if err != nil { + panic("Failed to create README file: " + err.Error()) + } + defer f.Close() + + for _, input := range inputs { + tmpl, err := template.ParseFiles(input) + if err != nil { + panic("Failed to parse README template: " + err.Error()) + } + + err = tmpl.Execute(f, data) + if err != nil { + panic(input + ": Failed to append README content: " + err.Error()) + } + } + +} From 53243e14241fb5f85a79da2245a879b25b2408d6 Mon Sep 17 00:00:00 2001 From: Ender Demirkaya Date: Mon, 24 Nov 2025 14:26:54 -0800 Subject: [PATCH 6/7] Add sample signal workflow Signed-off-by: Ender Demirkaya --- new_samples/signal/generator/README.md | 23 ++++++++++++++ .../signal/generator/README_specific.md | 30 +++++++++++++++++++ new_samples/signal/generator/generate.go | 16 ++++++++++ 3 files changed, 69 insertions(+) create mode 100644 new_samples/signal/generator/README.md create mode 100644 new_samples/signal/generator/README_specific.md create mode 100644 new_samples/signal/generator/generate.go diff --git a/new_samples/signal/generator/README.md b/new_samples/signal/generator/README.md new file mode 100644 index 0000000..1da3502 --- /dev/null +++ b/new_samples/signal/generator/README.md @@ -0,0 +1,23 @@ + + + +# 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. diff --git a/new_samples/signal/generator/README_specific.md b/new_samples/signal/generator/README_specific.md new file mode 100644 index 0000000..afc66ad --- /dev/null +++ b/new_samples/signal/generator/README_specific.md @@ -0,0 +1,30 @@ +## Simple Signal 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 \ + --tl cadence-samples-worker \ + --et 60 \ + --workflow_type cadence_samples.SimpleSignalWorkflow +``` + +Verify that your workflow started. Your can find your worklow by looking at the "Workflow type" column. + +If this is your first sample, please refer to [HelloWorkflow sample](https://github.com/cadence-workflow/cadence-samples/tree/master/new_samples/hello_world) about how to view your workflows. + + +### Signal your workflow + +This workflow will need a signal to complete successfully. Below is how you can send a signal. In this example, we are sending a `bool` value `true` (JSON formatted) via the signal called `complete` + +```bash +cadence --env development \ + --domain cadence-samples \ + workflow signal \ + --wid \ + --name complete \ + --input 'true' +``` diff --git a/new_samples/signal/generator/generate.go b/new_samples/signal/generator/generate.go new file mode 100644 index 0000000..fca5329 --- /dev/null +++ b/new_samples/signal/generator/generate.go @@ -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: "Signal Workflow", + Workflows: []string{"SimpleSignalWorkflow"}, + Activities: []string{"SimpleSignalActivity"}, + } + + template.GenerateAll(data) +} + +// Implement custom generator below \ No newline at end of file From fe9bd5c219aaa3ebcda58346f3f4e58e0b37894b Mon Sep 17 00:00:00 2001 From: Ender Demirkaya Date: Mon, 24 Nov 2025 14:28:03 -0800 Subject: [PATCH 7/7] Add workflow code Signed-off-by: Ender Demirkaya --- new_samples/signal/README.md | 68 +++++++++++++ new_samples/signal/main.go | 20 ++++ new_samples/signal/simple_signal_workflow.go | 56 ++++++++++ new_samples/signal/worker.go | 101 +++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 new_samples/signal/README.md create mode 100644 new_samples/signal/main.go create mode 100644 new_samples/signal/simple_signal_workflow.go create mode 100644 new_samples/signal/worker.go diff --git a/new_samples/signal/README.md b/new_samples/signal/README.md new file mode 100644 index 0000000..5036970 --- /dev/null +++ b/new_samples/signal/README.md @@ -0,0 +1,68 @@ + + + +# Signal 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 + +## Simple Signal 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 \ + --tl cadence-samples-worker \ + --et 60 \ + --workflow_type cadence_samples.SimpleSignalWorkflow +``` + +Verify that your workflow started. Your can find your worklow by looking at the "Workflow type" column. + +If this is your first sample, please refer to [HelloWorkflow sample](https://github.com/cadence-workflow/cadence-samples/tree/master/new_samples/hello_world) about how to view your workflows. + + +### Signal your workflow + +This workflow will need a signal to complete successfully. Below is how you can send a signal. In this example, we are sending a `bool` value `true` (JSON formatted) via the signal called `complete` + +```bash +cadence --env development \ + --domain cadence-samples \ + workflow signal \ + --wid \ + --name complete \ + --input 'true' +``` + +## 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 + diff --git a/new_samples/signal/main.go b/new_samples/signal/main.go new file mode 100644 index 0000000..5893999 --- /dev/null +++ b/new_samples/signal/main.go @@ -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 +} diff --git a/new_samples/signal/simple_signal_workflow.go b/new_samples/signal/simple_signal_workflow.go new file mode 100644 index 0000000..125ed5e --- /dev/null +++ b/new_samples/signal/simple_signal_workflow.go @@ -0,0 +1,56 @@ +package main + +import ( + "context" + "go.uber.org/cadence/workflow" + "go.uber.org/cadence/activity" + "strconv" + "time" + "go.uber.org/zap" +) + +const ( + CompleteSignalChan = "complete" +) + +func SimpleSignalWorkflow(ctx workflow.Context) error { + ao := workflow.ActivityOptions{ + ScheduleToStartTimeout: time.Minute * 60, + StartToCloseTimeout: time.Minute * 60, + } + ctx = workflow.WithActivityOptions(ctx, ao) + logger := workflow.GetLogger(ctx) + logger.Info("SimpleSignalWorkflow started") + + var complete bool + completeChan := workflow.GetSignalChannel(ctx, CompleteSignalChan) + for { + s := workflow.NewSelector(ctx) + s.AddReceive(completeChan, func(ch workflow.Channel, ok bool) { + if ok { + ch.Receive(ctx, &complete) + } + logger.Info("Signal input: " + strconv.FormatBool(complete)) + }) + s.Select(ctx) + + var result string + err := workflow.ExecuteActivity(ctx, SimpleSignalActivity, complete).Get(ctx, &result) + if err != nil { + return err + } + logger.Info("Activity result: " + result) + if complete { + return nil + } + } +} + +func SimpleSignalActivity(ctx context.Context, complete bool) (string, error) { + logger := activity.GetLogger(ctx) + logger.Info("SimpleSignalActivity started, a new signal has been received", zap.Bool("complete", complete)) + if complete { + return "Workflow will complete now", nil + } + return "Workflow will continue to run", nil +} diff --git a/new_samples/signal/worker.go b/new_samples/signal/worker.go new file mode 100644 index 0000000..ee0d8d4 --- /dev/null +++ b/new_samples/signal/worker.go @@ -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(SimpleSignalWorkflow, workflow.RegisterOptions{Name: "cadence_samples.SimpleSignalWorkflow"}) + w.RegisterActivityWithOptions(SimpleSignalActivity, activity.RegisterOptions{Name: "cadence_samples.SimpleSignalActivity"}) + + 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 +}