Skip to content

Commit 1c52b7c

Browse files
committed
Prepare replayer-adapter-go for publishing
1 parent 55849f6 commit 1c52b7c

File tree

4 files changed

+99
-13
lines changed

4 files changed

+99
-13
lines changed

replayer-adapter-go/README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Temporal Go Replayer Adapter
2+
3+
A Go adapter for debugging Temporal workflows by replaying execution history with breakpoint support.
4+
5+
## Installation
6+
7+
```bash
8+
go get github.com/phuongdnguyen/temporal-goland-plugin/replayer-adapter-go
9+
```
10+
11+
## Overview
12+
13+
This adapter provides workflow replay functionality for Temporal Go SDK applications, enabling debugging through:
14+
15+
- **Standalone Mode**: Replay workflows using local history files
16+
- **IDE Mode**: Replay workflows with debugger UI integration
17+
18+
## Features
19+
20+
- Workflow history replay with breakpoint support
21+
- Interceptor-based debugging hooks
22+
- Support for both standalone and IDE-integrated debugging
23+
- Activity and workflow execution tracking
24+
25+
## Usage
26+
27+
```go
28+
import (
29+
"go.temporal.io/sdk/worker"
30+
replayeradapter "github.com/phuongdnguyen/temporal-goland-plugin/replayer-adapter-go"
31+
)
32+
33+
// Set replay mode
34+
replayeradapter.SetReplayMode(replayeradapter.ReplayModeIde)
35+
36+
// Configure replay options
37+
opts := replayeradapter.ReplayOptions{
38+
WorkerReplayOptions: worker.WorkflowReplayerOptions{},
39+
HistoryFilePath: "/path/to/history.json", // for standalone mode
40+
}
41+
42+
// Replay workflow
43+
err := replayeradapter.Replay(opts, yourWorkflow)
44+
if err != nil {
45+
log.Fatal(err)
46+
}
47+
```
48+
49+
### Standalone Mode Example
50+
51+
```go
52+
// Set breakpoints at specific event IDs
53+
replayeradapter.SetBreakpoints([]int{1, 5, 10})
54+
55+
// Set standalone mode
56+
replayeradapter.SetReplayMode(replayeradapter.ReplayModeStandalone)
57+
58+
// Configure with history file
59+
opts := replayeradapter.ReplayOptions{
60+
WorkerReplayOptions: worker.WorkflowReplayerOptions{},
61+
HistoryFilePath: "/path/to/your/workflow-history.json",
62+
}
63+
64+
// Replay workflow
65+
err := replayeradapter.Replay(opts, yourWorkflowFunction)
66+
```
67+
68+
## Dependencies
69+
70+
- `go.temporal.io/sdk` v1.35.0
71+
- `go.temporal.io/api` v1.49.1
72+
- `github.com/bufbuild/connect-go` v1.10.0
73+
74+
## Architecture
75+
76+
The adapter uses Temporal SDK interceptors to hook into workflow execution:
77+
78+
- **Inbound Interceptors**: Track workflow and activity execution entry points
79+
- **Outbound Interceptors**: Monitor workflow operations (activities, timers, signals, etc.)
80+
- **Breakpoint Management**: Support for setting and checking breakpoints during replay

replayer-adapter-go/go.mod

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
module replayer_adapter
1+
module github.com/phuongdnguyen/temporal-goland-plugin/replayer-adapter-go
22

33
go 1.23.0
44

55
require (
6-
github.com/bufbuild/connect-go v1.10.0
76
go.temporal.io/api v1.49.1
87
go.temporal.io/sdk v1.35.0
9-
google.golang.org/protobuf v1.36.5
108
)
119

1210
require (
@@ -30,5 +28,6 @@ require (
3028
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
3129
google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
3230
google.golang.org/grpc v1.66.0 // indirect
31+
google.golang.org/protobuf v1.36.5 // indirect
3332
gopkg.in/yaml.v3 v3.0.1 // indirect
3433
)

replayer-adapter-go/go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
22
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
33
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
4-
github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg=
5-
github.com/bufbuild/connect-go v1.10.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8=
64
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
75
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
86
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=

replayer-adapter-go/replayer.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Package replayer_adapter_go provides workflow replay functionality for Temporal Go SDK applications.
2+
// It enables debugging through standalone mode (using local history files) and IDE mode (with debugger UI integration).
13
package replayer_adapter_go
24

35
import (
@@ -44,23 +46,30 @@ var (
4446
breakpoints = make(map[int]struct{})
4547
)
4648

49+
// ReplayOptions configures the workflow replay behavior.
4750
type ReplayOptions struct {
4851
WorkerReplayOptions worker.WorkflowReplayerOptions
4952
// HistoryFilePath only used in Standalone mode, absolute path to the history file
5053
HistoryFilePath string
5154
}
5255

53-
// SetBreakpoints only used in Standalone mode
56+
// SetBreakpoints sets the event IDs where execution should pause during replay.
57+
// This function is only used in Standalone mode.
5458
func SetBreakpoints(eventIds []int) {
5559
for _, eventId := range eventIds {
5660
breakpoints[eventId] = struct{}{}
5761
}
5862
}
5963

64+
// SetReplayMode configures the replay mode (Standalone or IDE).
6065
func SetReplayMode(m ReplayMode) {
6166
mode = m
6267
}
6368

69+
// Replay executes workflow replay with the specified options and workflow function.
70+
// The behavior depends on the configured ReplayMode:
71+
// - ReplayModeStandalone: replays using the history file specified in opts.HistoryFilePath
72+
// - ReplayModeIde: replays by fetching history from the IDE debugger interface
6473
func Replay(opts ReplayOptions, wf any) error {
6574
fmt.Printf("Replaying in mode %s", mode)
6675
if mode == ReplayModeStandalone {
@@ -214,43 +223,43 @@ func getHistoryFromIDE() (*historypb.History, error) {
214223
port = "54578"
215224
}
216225
runnerAddr := "http://127.0.0.1:" + port
217-
226+
218227
// Create client with timeout to match other implementations
219228
client := &http.Client{Timeout: 5 * time.Second}
220229
resp, err := client.Get(runnerAddr + "/history")
221230
if err != nil {
222231
return nil, fmt.Errorf("could not get history from IDE: %v", err)
223232
}
224233
defer resp.Body.Close()
225-
234+
226235
if resp.StatusCode != http.StatusOK {
227236
return nil, fmt.Errorf("could not get history from IDE: HTTP %d", resp.StatusCode)
228237
}
229-
238+
230239
body, err := io.ReadAll(resp.Body)
231240
if err != nil {
232241
return nil, fmt.Errorf("could not read history response: %v", err)
233242
}
234-
243+
235244
// Convert JSON response to protobuf format
236245
hist, err := extractHistoryFromJsonBytes(body, 0)
237246
if err != nil {
238247
return nil, fmt.Errorf("could not parse history: %v", err)
239248
}
240-
249+
241250
// Store runner address for breakpoint checks
242251
debuggerAddr = runnerAddr
243252
return hist, nil
244253
}
245254

246255
func extractHistoryFromJsonBytes(body []byte, lastEventID int64) (hist *historypb.History, err error) {
247256
fmt.Printf("extractHistoryFromJsonBytes, body length: %d bytes\n", len(body))
248-
257+
249258
// Validate that we have JSON data
250259
if len(body) == 0 {
251260
return nil, fmt.Errorf("empty history data received")
252261
}
253-
262+
254263
opts := temporalproto.CustomJSONUnmarshalOptions{
255264
DiscardUnknown: true,
256265
}

0 commit comments

Comments
 (0)