Skip to content

Commit 0a5ed51

Browse files
committed
feat: Simplify worker boilerplate with common helper
Add new_samples/common/cadence.go with NewCadenceClient() helper that handles all gRPC/YARPC setup in one function call. Before: worker.go was ~100 lines with manual YARPC dispatcher setup After: worker.go is ~40 lines focused on workflow/activity registration Key changes: - common.NewCadenceClient() encapsulates all gRPC connection boilerplate - Removed explicit logger/scope setup (Cadence provides defaults) - Template updated to use the common helper This is a stepping stone toward moving NewGrpcClient() to cadence-client itself (per Nathanael's proposal in Slack). Signed-off-by: Diana Zawadzki <[email protected]>
1 parent 2fd7776 commit 0a5ed51

File tree

5 files changed

+134
-260
lines changed

5 files changed

+134
-260
lines changed

new_samples/common/cadence.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Package common provides shared utilities for Cadence samples.
2+
// This simplifies worker setup by providing a one-liner for client creation.
3+
//
4+
// Once cadence-client adds NewGrpcClient(), this package can be replaced
5+
// with a direct import from go.uber.org/cadence/client.
6+
package common
7+
8+
import (
9+
"fmt"
10+
11+
apiv1 "github.com/uber/cadence-idl/go/proto/api/v1"
12+
"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
13+
"go.uber.org/cadence/compatibility"
14+
"go.uber.org/yarpc"
15+
"go.uber.org/yarpc/peer"
16+
"go.uber.org/yarpc/peer/hostport"
17+
"go.uber.org/yarpc/transport/grpc"
18+
)
19+
20+
const (
21+
// DefaultHostPort is the default Cadence frontend address
22+
DefaultHostPort = "127.0.0.1:7833"
23+
// DefaultDomain is the default domain for samples
24+
DefaultDomain = "cadence-samples"
25+
// DefaultTaskList is the default task list for samples
26+
DefaultTaskList = "cadence-samples-worker"
27+
// CadenceService is the service name for YARPC
28+
CadenceService = "cadence-frontend"
29+
)
30+
31+
// NewCadenceClient creates a new Cadence client connected via gRPC.
32+
// This is a simplified helper that handles all the YARPC/gRPC boilerplate.
33+
//
34+
// Parameters:
35+
// - caller: The name of the calling service (used for tracing)
36+
// - hostPort: The Cadence frontend address (e.g., "localhost:7833")
37+
// - dialOptions: Optional gRPC dial options (e.g., for TLS)
38+
//
39+
// Example:
40+
//
41+
// client, err := common.NewCadenceClient("my-worker", "localhost:7833")
42+
func NewCadenceClient(caller, hostPort string, dialOptions ...grpc.DialOption) (workflowserviceclient.Interface, error) {
43+
grpcTransport := grpc.NewTransport()
44+
45+
myChooser := peer.NewSingle(
46+
hostport.Identify(hostPort),
47+
grpcTransport.NewDialer(dialOptions...),
48+
)
49+
outbound := grpcTransport.NewOutbound(myChooser)
50+
51+
dispatcher := yarpc.NewDispatcher(yarpc.Config{
52+
Name: caller,
53+
Outbounds: yarpc.Outbounds{
54+
CadenceService: {Unary: outbound},
55+
},
56+
})
57+
if err := dispatcher.Start(); err != nil {
58+
return nil, fmt.Errorf("failed to start dispatcher: %w", err)
59+
}
60+
61+
clientConfig := dispatcher.ClientConfig(CadenceService)
62+
63+
return compatibility.NewThrift2ProtoAdapter(
64+
apiv1.NewDomainAPIYARPCClient(clientConfig),
65+
apiv1.NewWorkflowAPIYARPCClient(clientConfig),
66+
apiv1.NewWorkerAPIYARPCClient(clientConfig),
67+
apiv1.NewVisibilityAPIYARPCClient(clientConfig),
68+
), nil
69+
}
70+
71+
// MustNewCadenceClient is like NewCadenceClient but panics on error.
72+
// Useful for sample code where error handling would add noise.
73+
func MustNewCadenceClient(caller, hostPort string, dialOptions ...grpc.DialOption) workflowserviceclient.Interface {
74+
client, err := NewCadenceClient(caller, hostPort, dialOptions...)
75+
if err != nil {
76+
panic(err)
77+
}
78+
return client
79+
}

new_samples/hello_world/README.md

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@ cadence --env development \
4343
--input '{"message":"Cadence"}'
4444
```
4545

46-
You should see output like this:
47-
48-
![Trigger command output](images/02-trigger-command-started-workflow.png)
49-
50-
And the worker will log the completed workflow:
51-
52-
![Worker output showing workflow completed](images/01-worker-output-workflow-completed.png)
53-
5446
Here are the details to this command:
5547

5648
* `--domain` option describes under which domain to run this workflow
@@ -68,17 +60,8 @@ To see more options run `cadence --help`
6860

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

71-
![Workflow list showing completed workflow](images/03-web-ui-workflow-list-completed.png)
72-
73-
Click on the workflow to see details:
74-
7563
* In Summary tab, you will see the input and output to your workflow
76-
77-
![Summary tab](images/04-web-ui-summary-tab.png)
78-
79-
* Click on History tab to see individual steps. Expand an activity to see its result:
80-
81-
![History tab with activity result](images/05-web-ui-history-activity-result.png)
64+
* Click on History tab to see individual steps.
8265

8366
#### CLI
8467

@@ -111,14 +94,6 @@ cadence --env development \
11194
--wid <workflow_id>
11295
```
11396

114-
## Troubleshooting
115-
116-
If you see port conflicts when starting Docker, use `lsof` to find what's using the port:
117-
118-
![Docker port conflict troubleshooting](images/06-docker-port-conflict-troubleshooting.png)
119-
120-
See the main [README](../../README.md#docker-troubleshooting) for detailed Docker troubleshooting steps.
121-
12297
## References
12398

12499
* The website: https://cadenceworkflow.io

new_samples/hello_world/worker.go

Lines changed: 18 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,41 @@
11
// THIS IS A GENERATED FILE
22
// PLEASE DO NOT EDIT
33

4-
// Package worker implements a Cadence worker with basic configurations.
54
package main
65

76
import (
8-
"github.com/uber-go/tally"
9-
apiv1 "github.com/uber/cadence-idl/go/proto/api/v1"
10-
"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
7+
"github.com/uber-common/cadence-samples/new_samples/common"
118
"go.uber.org/cadence/activity"
12-
"go.uber.org/cadence/compatibility"
139
"go.uber.org/cadence/worker"
1410
"go.uber.org/cadence/workflow"
15-
"go.uber.org/yarpc"
16-
"go.uber.org/yarpc/peer"
17-
yarpchostport "go.uber.org/yarpc/peer/hostport"
18-
"go.uber.org/yarpc/transport/grpc"
1911
"go.uber.org/zap"
20-
"go.uber.org/zap/zapcore"
2112
)
2213

23-
const (
24-
HostPort = "127.0.0.1:7833"
25-
Domain = "cadence-samples"
26-
// TaskListName identifies set of client workflows, activities, and workers.
27-
// It could be your group or client or application name.
28-
TaskListName = "cadence-samples-worker"
29-
ClientName = "cadence-samples-worker"
30-
CadenceService = "cadence-frontend"
31-
)
32-
33-
// StartWorker creates and starts a basic Cadence worker.
14+
// StartWorker creates and starts a Cadence worker.
3415
func StartWorker() {
35-
logger, cadenceClient := BuildLogger(), BuildCadenceClient()
36-
workerOptions := worker.Options{
37-
Logger: logger,
38-
MetricsScope: tally.NewTestScope(TaskListName, nil),
39-
}
16+
// Create Cadence client - all gRPC/YARPC boilerplate is handled by the helper
17+
cadenceClient := common.MustNewCadenceClient(
18+
common.DefaultTaskList,
19+
common.DefaultHostPort,
20+
)
4021

4122
w := worker.New(
4223
cadenceClient,
43-
Domain,
44-
TaskListName,
45-
workerOptions)
46-
// HelloWorld workflow registration
47-
w.RegisterWorkflowWithOptions(HelloWorldWorkflow, workflow.RegisterOptions{Name: "cadence_samples.HelloWorldWorkflow"})
48-
w.RegisterActivityWithOptions(HelloWorldActivity, activity.RegisterOptions{Name: "cadence_samples.HelloWorldActivity"})
49-
50-
err := w.Start()
51-
if err != nil {
52-
panic("Failed to start worker: " + err.Error())
53-
}
54-
logger.Info("Started Worker.", zap.String("worker", TaskListName))
55-
56-
}
57-
58-
func BuildCadenceClient(dialOptions ...grpc.DialOption) workflowserviceclient.Interface {
59-
grpcTransport := grpc.NewTransport()
60-
// Create a single peer chooser that identifies the host/port and configures
61-
// a gRPC dialer with TLS credentials
62-
myChooser := peer.NewSingle(
63-
yarpchostport.Identify(HostPort),
64-
grpcTransport.NewDialer(dialOptions...),
24+
common.DefaultDomain,
25+
common.DefaultTaskList,
26+
worker.Options{},
6527
)
66-
outbound := grpcTransport.NewOutbound(myChooser)
67-
68-
dispatcher := yarpc.NewDispatcher(yarpc.Config{
69-
Name: ClientName,
70-
Outbounds: yarpc.Outbounds{
71-
CadenceService: {Unary: outbound},
72-
},
73-
})
74-
if err := dispatcher.Start(); err != nil {
75-
panic("Failed to start dispatcher: " + err.Error())
76-
}
77-
78-
clientConfig := dispatcher.ClientConfig(CadenceService)
7928

80-
// Create a compatibility adapter that wraps proto-based YARPC clients
81-
// to provide a unified interface for domain, workflow, worker, and visibility APIs
82-
return compatibility.NewThrift2ProtoAdapter(
83-
apiv1.NewDomainAPIYARPCClient(clientConfig),
84-
apiv1.NewWorkflowAPIYARPCClient(clientConfig),
85-
apiv1.NewWorkerAPIYARPCClient(clientConfig),
86-
apiv1.NewVisibilityAPIYARPCClient(clientConfig),
87-
)
88-
}
29+
// Register workflows
30+
w.RegisterWorkflowWithOptions(HelloWorldWorkflow, workflow.RegisterOptions{Name: "cadence_samples.HelloWorldWorkflow"})
8931

90-
func BuildLogger() *zap.Logger {
91-
config := zap.NewDevelopmentConfig()
92-
config.Level.SetLevel(zapcore.InfoLevel)
32+
// Register activities
33+
w.RegisterActivityWithOptions(HelloWorldActivity, activity.RegisterOptions{Name: "cadence_samples.HelloWorldActivity"})
9334

94-
var err error
95-
logger, err := config.Build()
96-
if err != nil {
97-
panic("Failed to setup logger: " + err.Error())
35+
if err := w.Start(); err != nil {
36+
panic("Failed to start worker: " + err.Error())
9837
}
9938

100-
return logger
39+
logger, _ := zap.NewDevelopment()
40+
logger.Info("Started Worker.", zap.String("taskList", common.DefaultTaskList))
10141
}

new_samples/signal/worker.go

Lines changed: 18 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,41 @@
11
// THIS IS A GENERATED FILE
22
// PLEASE DO NOT EDIT
33

4-
// Package worker implements a Cadence worker with basic configurations.
54
package main
65

76
import (
8-
"github.com/uber-go/tally"
9-
apiv1 "github.com/uber/cadence-idl/go/proto/api/v1"
10-
"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
7+
"github.com/uber-common/cadence-samples/new_samples/common"
118
"go.uber.org/cadence/activity"
12-
"go.uber.org/cadence/compatibility"
139
"go.uber.org/cadence/worker"
1410
"go.uber.org/cadence/workflow"
15-
"go.uber.org/yarpc"
16-
"go.uber.org/yarpc/peer"
17-
yarpchostport "go.uber.org/yarpc/peer/hostport"
18-
"go.uber.org/yarpc/transport/grpc"
1911
"go.uber.org/zap"
20-
"go.uber.org/zap/zapcore"
2112
)
2213

23-
const (
24-
HostPort = "127.0.0.1:7833"
25-
Domain = "cadence-samples"
26-
// TaskListName identifies set of client workflows, activities, and workers.
27-
// It could be your group or client or application name.
28-
TaskListName = "cadence-samples-worker"
29-
ClientName = "cadence-samples-worker"
30-
CadenceService = "cadence-frontend"
31-
)
32-
33-
// StartWorker creates and starts a basic Cadence worker.
14+
// StartWorker creates and starts a Cadence worker.
3415
func StartWorker() {
35-
logger, cadenceClient := BuildLogger(), BuildCadenceClient()
36-
workerOptions := worker.Options{
37-
Logger: logger,
38-
MetricsScope: tally.NewTestScope(TaskListName, nil),
39-
}
16+
// Create Cadence client - all gRPC/YARPC boilerplate is handled by the helper
17+
cadenceClient := common.MustNewCadenceClient(
18+
common.DefaultTaskList,
19+
common.DefaultHostPort,
20+
)
4021

4122
w := worker.New(
4223
cadenceClient,
43-
Domain,
44-
TaskListName,
45-
workerOptions)
46-
// HelloWorld workflow registration
47-
w.RegisterWorkflowWithOptions(SimpleSignalWorkflow, workflow.RegisterOptions{Name: "cadence_samples.SimpleSignalWorkflow"})
48-
w.RegisterActivityWithOptions(SimpleSignalActivity, activity.RegisterOptions{Name: "cadence_samples.SimpleSignalActivity"})
49-
50-
err := w.Start()
51-
if err != nil {
52-
panic("Failed to start worker: " + err.Error())
53-
}
54-
logger.Info("Started Worker.", zap.String("worker", TaskListName))
55-
56-
}
57-
58-
func BuildCadenceClient(dialOptions ...grpc.DialOption) workflowserviceclient.Interface {
59-
grpcTransport := grpc.NewTransport()
60-
// Create a single peer chooser that identifies the host/port and configures
61-
// a gRPC dialer with TLS credentials
62-
myChooser := peer.NewSingle(
63-
yarpchostport.Identify(HostPort),
64-
grpcTransport.NewDialer(dialOptions...),
24+
common.DefaultDomain,
25+
common.DefaultTaskList,
26+
worker.Options{},
6527
)
66-
outbound := grpcTransport.NewOutbound(myChooser)
67-
68-
dispatcher := yarpc.NewDispatcher(yarpc.Config{
69-
Name: ClientName,
70-
Outbounds: yarpc.Outbounds{
71-
CadenceService: {Unary: outbound},
72-
},
73-
})
74-
if err := dispatcher.Start(); err != nil {
75-
panic("Failed to start dispatcher: " + err.Error())
76-
}
77-
78-
clientConfig := dispatcher.ClientConfig(CadenceService)
7928

80-
// Create a compatibility adapter that wraps proto-based YARPC clients
81-
// to provide a unified interface for domain, workflow, worker, and visibility APIs
82-
return compatibility.NewThrift2ProtoAdapter(
83-
apiv1.NewDomainAPIYARPCClient(clientConfig),
84-
apiv1.NewWorkflowAPIYARPCClient(clientConfig),
85-
apiv1.NewWorkerAPIYARPCClient(clientConfig),
86-
apiv1.NewVisibilityAPIYARPCClient(clientConfig),
87-
)
88-
}
29+
// Register workflows
30+
w.RegisterWorkflowWithOptions(SimpleSignalWorkflow, workflow.RegisterOptions{Name: "cadence_samples.SimpleSignalWorkflow"})
8931

90-
func BuildLogger() *zap.Logger {
91-
config := zap.NewDevelopmentConfig()
92-
config.Level.SetLevel(zapcore.InfoLevel)
32+
// Register activities
33+
w.RegisterActivityWithOptions(SimpleSignalActivity, activity.RegisterOptions{Name: "cadence_samples.SimpleSignalActivity"})
9334

94-
var err error
95-
logger, err := config.Build()
96-
if err != nil {
97-
panic("Failed to setup logger: " + err.Error())
35+
if err := w.Start(); err != nil {
36+
panic("Failed to start worker: " + err.Error())
9837
}
9938

100-
return logger
39+
logger, _ := zap.NewDevelopment()
40+
logger.Info("Started Worker.", zap.String("taskList", common.DefaultTaskList))
10141
}

0 commit comments

Comments
 (0)