|
| 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). |
1 | 3 | package replayer_adapter_go |
2 | 4 |
|
3 | 5 | import ( |
@@ -44,23 +46,30 @@ var ( |
44 | 46 | breakpoints = make(map[int]struct{}) |
45 | 47 | ) |
46 | 48 |
|
| 49 | +// ReplayOptions configures the workflow replay behavior. |
47 | 50 | type ReplayOptions struct { |
48 | 51 | WorkerReplayOptions worker.WorkflowReplayerOptions |
49 | 52 | // HistoryFilePath only used in Standalone mode, absolute path to the history file |
50 | 53 | HistoryFilePath string |
51 | 54 | } |
52 | 55 |
|
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. |
54 | 58 | func SetBreakpoints(eventIds []int) { |
55 | 59 | for _, eventId := range eventIds { |
56 | 60 | breakpoints[eventId] = struct{}{} |
57 | 61 | } |
58 | 62 | } |
59 | 63 |
|
| 64 | +// SetReplayMode configures the replay mode (Standalone or IDE). |
60 | 65 | func SetReplayMode(m ReplayMode) { |
61 | 66 | mode = m |
62 | 67 | } |
63 | 68 |
|
| 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 |
64 | 73 | func Replay(opts ReplayOptions, wf any) error { |
65 | 74 | fmt.Printf("Replaying in mode %s", mode) |
66 | 75 | if mode == ReplayModeStandalone { |
@@ -214,43 +223,43 @@ func getHistoryFromIDE() (*historypb.History, error) { |
214 | 223 | port = "54578" |
215 | 224 | } |
216 | 225 | runnerAddr := "http://127.0.0.1:" + port |
217 | | - |
| 226 | + |
218 | 227 | // Create client with timeout to match other implementations |
219 | 228 | client := &http.Client{Timeout: 5 * time.Second} |
220 | 229 | resp, err := client.Get(runnerAddr + "/history") |
221 | 230 | if err != nil { |
222 | 231 | return nil, fmt.Errorf("could not get history from IDE: %v", err) |
223 | 232 | } |
224 | 233 | defer resp.Body.Close() |
225 | | - |
| 234 | + |
226 | 235 | if resp.StatusCode != http.StatusOK { |
227 | 236 | return nil, fmt.Errorf("could not get history from IDE: HTTP %d", resp.StatusCode) |
228 | 237 | } |
229 | | - |
| 238 | + |
230 | 239 | body, err := io.ReadAll(resp.Body) |
231 | 240 | if err != nil { |
232 | 241 | return nil, fmt.Errorf("could not read history response: %v", err) |
233 | 242 | } |
234 | | - |
| 243 | + |
235 | 244 | // Convert JSON response to protobuf format |
236 | 245 | hist, err := extractHistoryFromJsonBytes(body, 0) |
237 | 246 | if err != nil { |
238 | 247 | return nil, fmt.Errorf("could not parse history: %v", err) |
239 | 248 | } |
240 | | - |
| 249 | + |
241 | 250 | // Store runner address for breakpoint checks |
242 | 251 | debuggerAddr = runnerAddr |
243 | 252 | return hist, nil |
244 | 253 | } |
245 | 254 |
|
246 | 255 | func extractHistoryFromJsonBytes(body []byte, lastEventID int64) (hist *historypb.History, err error) { |
247 | 256 | fmt.Printf("extractHistoryFromJsonBytes, body length: %d bytes\n", len(body)) |
248 | | - |
| 257 | + |
249 | 258 | // Validate that we have JSON data |
250 | 259 | if len(body) == 0 { |
251 | 260 | return nil, fmt.Errorf("empty history data received") |
252 | 261 | } |
253 | | - |
| 262 | + |
254 | 263 | opts := temporalproto.CustomJSONUnmarshalOptions{ |
255 | 264 | DiscardUnknown: true, |
256 | 265 | } |
|
0 commit comments