Skip to content

Commit 858404c

Browse files
authored
Adding Directives + Using NewBatchFuture for Concurrency Example (cadence-workflow#7170)
1 parent bc0fa89 commit 858404c

File tree

1 file changed

+26
-33
lines changed

1 file changed

+26
-33
lines changed

.cursor/rules/CADENCE-WORKFLOWS.mdc

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Follow these rules to ensure deterministic, reliable, and maintainable Cadence w
1313

1414
Never iterate directly over Go maps in Cadence workflows. The iteration order is random and breaks determinism required for workflow replay. Always sort map keys before iterating.
1515

16-
**Good Example:**
16+
**USE**
1717
```go
1818
keys := make([]string, 0, len(myMap))
1919
for key := range myMap {
@@ -26,7 +26,7 @@ for _, key := range keys {
2626
}
2727
```
2828

29-
**Bad Example:**
29+
**NEVER USE**
3030
```go
3131
for key, value := range myMap {
3232
workflow.GetLogger(ctx).Info("Key:", key, "Value:", value)
@@ -39,7 +39,7 @@ for key, value := range myMap {
3939

4040
Do not use native Go goroutines inside Cadence workflows. Use `workflow.Go` to create Cadence-managed concurrent threads for deterministic execution and replay.
4141

42-
**Good Example:**
42+
**USE**
4343
```go
4444
workflow.Go(ctx, func(ctx workflow.Context) {
4545
activityInput := "process this"
@@ -50,7 +50,7 @@ workflow.Go(ctx, func(ctx workflow.Context) {
5050
})
5151
```
5252

53-
**Bad Example:**
53+
**NEVER USE**
5454
```go
5555
go func() {
5656
err := YourExternalFunction()
@@ -66,31 +66,24 @@ go func() {
6666

6767
Do not launch many activities or child workflows concurrently without limiting concurrency. Use a non-blocking pattern (similar to array) to control parallelism and avoid overwhelming workers.
6868

69-
**Good Example:**
69+
**USE**
7070
```go
71-
const maxConcurrent = 3
72-
var futures []workflow.Future
73-
sem := 0
71+
const batchSize = 3
72+
var futures []func(ctx workflow.Context) workflow.Future
7473
for _, input := range inputs {
75-
if sem == maxConcurrent {
76-
if err := futures[0].Get(ctx, nil); err != nil {
77-
workflow.GetLogger(ctx).Error("Activity failed", "Error", err)
78-
}
79-
futures = futures[1:]
80-
sem--
81-
}
82-
future := workflow.ExecuteActivity(ctx, YourActivity, input).Get(ctx, nil)
83-
futures = append(futures, future)
84-
sem++
74+
activityInput := input
75+
futures = append(futures, func(ctx workflow.Context) workflow.Future {
76+
return workflow.ExecuteActivity(ctx, "Activity Name", activityInput)
77+
})
8578
}
86-
for _, future := range futures {
87-
if err := future.Get(ctx, nil); err != nil {
88-
workflow.GetLogger(ctx).Error("Activity failed", "Error", err)
89-
}
79+
batchFuture, err := x.NewBatchFuture(ctx, batchSize, futures)
80+
if err != nil {
81+
return fmt.Errorf("failed to create batch future: %w", err)
9082
}
83+
return batchFuture.Get(ctx, nil)
9184
```
9285

93-
**Bad Example:**
86+
**NEVER USE**
9487
```go
9588
for _, input := range inputs {
9689
workflow.Go(ctx, func(ctx workflow.Context) {
@@ -108,13 +101,13 @@ for _, input := range inputs {
108101

109102
Never use `time.Now()` inside a Cadence workflow. Use `workflow.Now(ctx)` for deterministic, replayable time.
110103

111-
**Good Example:**
104+
**USE**
112105
```go
113106
now := workflow.Now(ctx)
114107
workflow.GetLogger(ctx).Info("Current time:", zap.Time("timestamp", now))
115108
```
116109

117-
**Bad Example:**
110+
**NEVER USE**
118111
```go
119112
now := time.Now()
120113
workflow.GetLogger(ctx).Info("Current time:", zap.Time("timestamp", now))
@@ -126,7 +119,7 @@ workflow.GetLogger(ctx).Info("Current time:", zap.Time("timestamp", now))
126119

127120
Do not use dynamic signal names in workflows. Always use static, predefined signal names to ensure deterministic signal handling and replay.
128121

129-
**Good Example:**
122+
**USE**
130123
```go
131124
func MyWorkflow(ctx workflow.Context) error {
132125
signalChan := workflow.GetSignalChannel(ctx, "statusUpdate")
@@ -141,7 +134,7 @@ func MyWorkflow(ctx workflow.Context) error {
141134
}
142135
```
143136

144-
**Bad Example:**
137+
**NEVER USE**
145138
```go
146139
func MyWorkflow(ctx workflow.Context, userID string) error {
147140
signalName := "signal_" + userID
@@ -156,7 +149,7 @@ func MyWorkflow(ctx workflow.Context, userID string) error {
156149

157150
Do not reuse the same workflow-id for frequent or continuous runs. This can cause hot shard problems. Use unique or distributed workflow-ids to spread load evenly.
158151

159-
**Good Example:**
152+
**USE**
160153
```go
161154
workflowOptions := client.StartWorkflowOptions{
162155
ID: fmt.Sprintf("order-workflow-%d", time.Now().UnixNano()),
@@ -165,7 +158,7 @@ workflowOptions := client.StartWorkflowOptions{
165158
we, err := c.ExecuteWorkflow(context.Background(), workflowOptions, OrderWorkflow, orderData)
166159
```
167160

168-
**Bad Example:**
161+
**NEVER USE**
169162
```go
170163
workflowOptions := client.StartWorkflowOptions{
171164
ID: "order-workflow",
@@ -180,7 +173,7 @@ we, err := c.ExecuteWorkflow(context.Background(), workflowOptions, OrderWorkflo
180173

181174
Never use `time.Sleep()` in a Cadence workflow. Use `workflow.Sleep(ctx, duration)` for deterministic, replayable sleep.
182175

183-
**Good Example:**
176+
**USE**
184177
```go
185178
func MyWorkflow(ctx workflow.Context) error {
186179
workflow.GetLogger(ctx).Info("Sleeping for 10 seconds...")
@@ -193,7 +186,7 @@ func MyWorkflow(ctx workflow.Context) error {
193186
}
194187
```
195188

196-
**Bad Example:**
189+
**NEVER USE**
197190
```go
198191
func MyWorkflow(ctx workflow.Context) error {
199192
log.Println("Sleeping for 10 seconds...")
@@ -209,7 +202,7 @@ func MyWorkflow(ctx workflow.Context) error {
209202

210203
Always register workflows and activities with explicit string names and use those names when starting them. This improves decoupling and ensures consistent communication between workers and clients.
211204

212-
**Good Example:**
205+
**USE**
213206
```go
214207
activity.RegisterWithOptions(MyActivityFunc, activity.RegisterOptions{Name: "MyActivity"})
215208
workflow.RegisterWithOptions(MyWorkflowFunc, workflow.RegisterOptions{Name: "MyWorkflow"})
@@ -220,7 +213,7 @@ workflowOptions := client.StartWorkflowOptions{
220213
client.ExecuteWorkflow(ctx, workflowOptions, "MyWorkflow", inputData)
221214
```
222215

223-
**Bad Example:**
216+
**NEVER USE**
224217
```go
225218
workflow.Register(MyWorkflowFunc)
226219
activity.Register(MyActivityFunc)

0 commit comments

Comments
 (0)