Skip to content

Commit aaacf61

Browse files
Use templates
Signed-off-by: Ender Demirkaya <[email protected]>
1 parent a636924 commit aaacf61

File tree

9 files changed

+559
-0
lines changed

9 files changed

+559
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Cadence Samples
2+
3+
These are some samples to demonstrate various capabilities of Cadence client and server. You can learn more about cadence at:
4+
5+
* The website: https://cadenceworkflow.io
6+
* Cadence's server: https://github.com/uber/cadence
7+
* Cadence's Go client: https://github.com/uber-go/cadence-client
8+
9+
## Prerequisite
10+
11+
0. Install Cadence CLI. See instruction [here](https://cadenceworkflow.io/docs/cli/).
12+
1. Run the Cadence server:
13+
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`
14+
2. Run `docker compose -f docker/docker-compose.yml up` to start Cadence server
15+
3. See more details at https://github.com/uber/cadence/blob/master/README.md
16+
2. Once everything is up and running in Docker, open [localhost:8088](localhost:8088) to view Cadence UI.
17+
3. Register the `cadence-samples` domain:
18+
19+
```bash
20+
cadence --env development --domain cadence-samples domain register
21+
```
22+
23+
Refresh the [domains page](http://localhost:8088/domains) from step 2 to verify `cadence-samples` is registered.
24+
25+
## Steps to run sample
26+
27+
Inside the folder this sample is defined, run the following command:
28+
29+
```bash
30+
go run .
31+
```
32+
33+
This will call the main function in main.go which starts the worker, which will be execute the sample workflow code
34+
35+
### Start your workflow
36+
37+
This workflow takes an input message and greet you as response. Try the following CLI
38+
39+
```bash
40+
cadence --env development \
41+
--domain cadence-samples \
42+
workflow start \
43+
--workflow_type cadence_samples.HelloWorldWorkflow \
44+
--tl cadence-samples-worker \
45+
--et 60 \
46+
--input '{"message":"Cadence"}'
47+
```
48+
49+
Here are the details to this command:
50+
51+
* `--domain` option describes under which domain to run this workflow
52+
* `--env development` calls the "local" cadence server
53+
* `--workflow_type` option describes which workflow to execute
54+
* `-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
55+
* `--et` (or `--execution_timeout`) tells cadence server how long to wait until timing out the workflow
56+
* `--input` is the input to your workflow
57+
58+
To see more options run `cadence --help`
59+
60+
### View your workflow
61+
62+
#### Cadence UI (cadence-web)
63+
64+
Click on `cadence-samples` domain in cadence-web to view your workflow.
65+
66+
* In Summary tab, you will see the input and output to your workflow
67+
* Click on History tab to see individual steps.
68+
69+
#### CLI
70+
71+
List workflows using the following command:
72+
73+
```bash
74+
cadence --env development --domain cadence-samples --workflow list
75+
```
76+
77+
You can view an individual workflow by using the following command:
78+
79+
```bash
80+
cadence --env development \
81+
--domain cadence-samples \
82+
--workflow describe \
83+
--wid <workflow_id>
84+
```
85+
86+
* `workflow` is the noun to run commands within workflow scope
87+
* `describe` is the verb to return the summary of the workflow
88+
* `--wid` (or `--workflow_id`) is the option to pass the workflow id. If there are multiple "run"s, it will return the latest one.
89+
* (optional) `--rid` (or `--run_id`) is the option to pass the run id to describe a specific run, instead of the latest.
90+
91+
To view the entire history of the workflow, use the following command:
92+
93+
```bash
94+
cadence --env development \
95+
--domain cadence-samples \
96+
--workflow show \
97+
--wid <workflow_id>
98+
```
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
### Start your workflow
2+
3+
This workflow takes an input message and greet you as response. Try the following CLI
4+
5+
```bash
6+
cadence --env development \
7+
--domain cadence-samples \
8+
workflow start \
9+
--workflow_type cadence_samples.HelloWorldWorkflow \
10+
--tl cadence-samples-worker \
11+
--et 60 \
12+
--input '{"message":"Cadence"}'
13+
```
14+
15+
Here are the details to this command:
16+
17+
* `--domain` option describes under which domain to run this workflow
18+
* `--env development` calls the "local" cadence server
19+
* `--workflow_type` option describes which workflow to execute
20+
* `-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
21+
* `--et` (or `--execution_timeout`) tells cadence server how long to wait until timing out the workflow
22+
* `--input` is the input to your workflow
23+
24+
To see more options run `cadence --help`
25+
26+
### View your workflow
27+
28+
#### Cadence UI (cadence-web)
29+
30+
Click on `cadence-samples` domain in cadence-web to view your workflow.
31+
32+
* In Summary tab, you will see the input and output to your workflow
33+
* Click on History tab to see individual steps.
34+
35+
#### CLI
36+
37+
List workflows using the following command:
38+
39+
```bash
40+
cadence --env development --domain cadence-samples --workflow list
41+
```
42+
43+
You can view an individual workflow by using the following command:
44+
45+
```bash
46+
cadence --env development \
47+
--domain cadence-samples \
48+
--workflow describe \
49+
--wid <workflow_id>
50+
```
51+
52+
* `workflow` is the noun to run commands within workflow scope
53+
* `describe` is the verb to return the summary of the workflow
54+
* `--wid` (or `--workflow_id`) is the option to pass the workflow id. If there are multiple "run"s, it will return the latest one.
55+
* (optional) `--rid` (or `--run_id`) is the option to pass the run id to describe a specific run, instead of the latest.
56+
57+
To view the entire history of the workflow, use the following command:
58+
59+
```bash
60+
cadence --env development \
61+
--domain cadence-samples \
62+
--workflow show \
63+
--wid <workflow_id>
64+
```
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"os"
6+
"text/template"
7+
)
8+
9+
type TemplateData struct {
10+
Workflows []string
11+
Activities []string
12+
}
13+
14+
func main() {
15+
// Define the data for HelloWorld
16+
data := TemplateData{
17+
Workflows: []string{"HelloWorldWorkflow"},
18+
Activities: []string{"HelloWorldActivity"},
19+
}
20+
21+
// Generate worker.go
22+
generateFile("../../template/worker.tmpl", "../worker.go", data)
23+
println("Generated worker.go")
24+
25+
// Generate main.go
26+
generateFile("../../template/main.tmpl", "../main.go", data)
27+
println("Generated main.go")
28+
29+
// Generate README.md (combine template + specific)
30+
generateREADME("../../template/README.tmpl", "README_specific.md", "../README.md", data)
31+
println("Generated README.md")
32+
}
33+
34+
func generateFile(templatePath, outputPath string, data TemplateData) {
35+
tmpl, err := template.ParseFiles(templatePath)
36+
if err != nil {
37+
panic("Failed to parse template " + templatePath + ": " + err.Error())
38+
}
39+
40+
f, err := os.Create(outputPath)
41+
if err != nil {
42+
panic("Failed to create output file " + outputPath + ": " + err.Error())
43+
}
44+
defer f.Close()
45+
46+
err = tmpl.Execute(f, data)
47+
if err != nil {
48+
panic("Failed to execute template: " + err.Error())
49+
}
50+
}
51+
52+
func generateREADME(templatePath, specificPath, outputPath string, data TemplateData) {
53+
// Create output file
54+
f, err := os.Create(outputPath)
55+
if err != nil {
56+
panic("Failed to create README file: " + err.Error())
57+
}
58+
defer f.Close()
59+
60+
// First, write the generic template part
61+
tmpl, err := template.ParseFiles(templatePath)
62+
if err != nil {
63+
panic("Failed to parse README template: " + err.Error())
64+
}
65+
66+
err = tmpl.Execute(f, data)
67+
if err != nil {
68+
panic("Failed to execute README template: " + err.Error())
69+
}
70+
71+
// Then, append the specific content
72+
specific, err := os.Open(specificPath)
73+
if err != nil {
74+
panic("Failed to open specific README content: " + err.Error())
75+
}
76+
defer specific.Close()
77+
78+
_, err = io.Copy(f, specific)
79+
if err != nil {
80+
panic("Failed to append specific README content: " + err.Error())
81+
}
82+
}
83+
84+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/signal"
7+
"syscall"
8+
)
9+
10+
func main() {
11+
StartWorker()
12+
13+
done := make(chan os.Signal, 1)
14+
signal.Notify(done, syscall.SIGINT)
15+
fmt.Println("Cadence worker started, press ctrl+c to terminate...")
16+
<-done
17+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Package worker implements a Cadence worker with basic configurations.
2+
package main
3+
4+
import (
5+
"github.com/uber-go/tally"
6+
apiv1 "github.com/uber/cadence-idl/go/proto/api/v1"
7+
"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
8+
"go.uber.org/cadence/activity"
9+
"go.uber.org/cadence/compatibility"
10+
"go.uber.org/cadence/worker"
11+
"go.uber.org/cadence/workflow"
12+
"go.uber.org/yarpc"
13+
"go.uber.org/yarpc/peer"
14+
yarpchostport "go.uber.org/yarpc/peer/hostport"
15+
"go.uber.org/yarpc/transport/grpc"
16+
"go.uber.org/zap"
17+
"go.uber.org/zap/zapcore"
18+
)
19+
20+
const (
21+
HostPort = "127.0.0.1:7833"
22+
Domain = "cadence-samples"
23+
// TaskListName identifies set of client workflows, activities, and workers.
24+
// It could be your group or client or application name.
25+
TaskListName = "cadence-samples-worker"
26+
ClientName = "cadence-samples-worker"
27+
CadenceService = "cadence-frontend"
28+
)
29+
30+
// StartWorker creates and starts a basic Cadence worker.
31+
func StartWorker() {
32+
logger, cadenceClient := BuildLogger(), BuildCadenceClient()
33+
workerOptions := worker.Options{
34+
Logger: logger,
35+
MetricsScope: tally.NewTestScope(TaskListName, nil),
36+
}
37+
38+
w := worker.New(
39+
cadenceClient,
40+
Domain,
41+
TaskListName,
42+
workerOptions)
43+
// HelloWorld workflow registration
44+
w.RegisterWorkflowWithOptions(HelloWorldWorkflow, workflow.RegisterOptions{Name: "cadence_samples.HelloWorldWorkflow"})
45+
w.RegisterActivityWithOptions(HelloWorldActivity, activity.RegisterOptions{Name: "cadence_samples.HelloWorldActivity"})
46+
47+
err := w.Start()
48+
if err != nil {
49+
panic("Failed to start worker: " + err.Error())
50+
}
51+
logger.Info("Started Worker.", zap.String("worker", TaskListName))
52+
53+
}
54+
55+
func BuildCadenceClient(dialOptions ...grpc.DialOption) workflowserviceclient.Interface {
56+
grpcTransport := grpc.NewTransport()
57+
// Create a single peer chooser that identifies the host/port and configures
58+
// a gRPC dialer with TLS credentials
59+
myChooser := peer.NewSingle(
60+
yarpchostport.Identify(HostPort),
61+
grpcTransport.NewDialer(dialOptions...),
62+
)
63+
outbound := grpcTransport.NewOutbound(myChooser)
64+
65+
dispatcher := yarpc.NewDispatcher(yarpc.Config{
66+
Name: ClientName,
67+
Outbounds: yarpc.Outbounds{
68+
CadenceService: {Unary: outbound},
69+
},
70+
})
71+
if err := dispatcher.Start(); err != nil {
72+
panic("Failed to start dispatcher: " + err.Error())
73+
}
74+
75+
clientConfig := dispatcher.ClientConfig(CadenceService)
76+
77+
// Create a compatibility adapter that wraps proto-based YARPC clients
78+
// to provide a unified interface for domain, workflow, worker, and visibility APIs
79+
return compatibility.NewThrift2ProtoAdapter(
80+
apiv1.NewDomainAPIYARPCClient(clientConfig),
81+
apiv1.NewWorkflowAPIYARPCClient(clientConfig),
82+
apiv1.NewWorkerAPIYARPCClient(clientConfig),
83+
apiv1.NewVisibilityAPIYARPCClient(clientConfig),
84+
)
85+
}
86+
87+
func BuildLogger() *zap.Logger {
88+
config := zap.NewDevelopmentConfig()
89+
config.Level.SetLevel(zapcore.InfoLevel)
90+
91+
var err error
92+
logger, err := config.Build()
93+
if err != nil {
94+
panic("Failed to setup logger: " + err.Error())
95+
}
96+
97+
return logger
98+
}

0 commit comments

Comments
 (0)