Skip to content

feat(lua): workflow history replayer module - #547

Open
xepozz wants to merge 1 commit into
wippyai:mainfrom
xepozz:feature/lua-workflow-replayer
Open

feat(lua): workflow history replayer module#547
xepozz wants to merge 1 commit into
wippyai:mainfrom
xepozz:feature/lua-workflow-replayer

Conversation

@xepozz

@xepozz xepozz commented Aug 3, 2026

Copy link
Copy Markdown

Reason for This PR

Lua workflows have no way to test determinism / replay safety. Every other
Temporal SDK exposes a WorkflowReplayer to re-execute a recorded history and
catch non-deterministic changes, but there is no equivalent reachable from Lua
or the native test runner. Today such regressions surface only on a live
cluster (as replay panics after a worker restart), never in CI.

This PR adds a Lua-facing replayer so a test can assert a workflow.lua entry
replays deterministically against a recorded event history.

Description of Changes

New builtin module replayer that wraps the SDK's worker.WorkflowReplayer:

local replayer = require("replayer")
-- (true) on deterministic replay, (nil, err) on a non-determinism / mismatch
local ok, err = replayer.replay_json_file("app.foo:my_workflow", "history.json")
  • replay_json_file(workflow_id, history_json_path[, workflow_type_name])
    registers the runtime's existing dynamic workflow.DefinitionFactory on a
    WorkflowReplayer (the SDK registry accepts it as a WorkflowDefinitionFactory)
    and replays the history file produced by
    temporal workflow show --workflow-id <id> --output json.
  • The optional workflow_type_name overrides the registered type name for
    workflows that set a custom meta name; it defaults to workflow_id.
  • The data converter, context propagators, and worker interceptors are taken
    from the runtime context so payloads decode exactly as recorded.
  • Class ClassIO, ClassNondeterministic — usable from function.lua/tests,
    not from a workflow body. Registered via a boot component, consistent with the
    other Lua modules.

Files:

  • runtime/lua/modules/replayer/{module.go,types.go,module_test.go}
  • boot/components/runtime/lua/replayer.go (+ all.go, constants.go)
  • service/temporal/workflow/replay_integration_test.go

Tests: unit tests for bind + argument validation; an integration test that runs
a workflow on a dev server, fetches its history, and replays it (both in-memory
and via the JSON-file path) against the DefinitionFactory, asserting nil error.

Add a builtin `replayer` Lua module that exposes Temporal's WorkflowReplayer to
Lua so tests can verify a workflow.lua entry replays deterministically against a
recorded event history (equivalent to the Go/TS/Java WorkflowReplayer).

  local replayer = require("replayer")
  local ok, err = replayer.replay_json_file("app.foo:my_workflow", "history.json")

The module wraps worker.WorkflowReplayer and registers the runtime's existing
dynamic workflow.DefinitionFactory (the SDK registry accepts it as a
WorkflowDefinitionFactory). ClassIO — usable from function.lua/tests, not a
workflow body. Registered via a boot component mirroring the other lua modules.

Tests: unit tests for bind + argument validation; an integration test that runs
a Lua workflow on a dev server, fetches its history, and replays it against the
DefinitionFactory (nil error == deterministic).
Copilot AI review requested due to automatic review settings August 3, 2026 13:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Lua-facing replayer builtin module that wraps Temporal’s worker.WorkflowReplayer, enabling determinism/replay-safety tests for Lua workflows by replaying recorded workflow histories (including from JSON files).

Changes:

  • Introduces runtime/lua/modules/replayer Lua module with replay_json_file(...) binding and type manifest.
  • Registers the module via a new boot component so it’s available consistently with other Lua builtins.
  • Adds an integration test that runs a workflow, fetches its history, and validates replay (including JSON-file replay).

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
service/temporal/workflow/replay_integration_test.go New integration test that replays recorded history to validate deterministic replay behavior.
runtime/lua/modules/replayer/module.go Implements the Lua replayer module and replay_json_file binding.
runtime/lua/modules/replayer/types.go Adds the type manifest for the new Lua module.
runtime/lua/modules/replayer/module_test.go Adds unit tests for binding and argument/context validation behavior.
boot/components/runtime/lua/replayer.go Registers the new Lua module via boot component.
boot/components/runtime/lua/constants.go Adds the boot component name constant.
boot/components/runtime/lua/all.go Includes the new component in the default Lua component set.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to +19
moduleType := typ.NewInterface("replayer", []typ.Method{
{Name: "replay_json_file", Type: typ.Func().
Param("workflow_id", typ.Any).
Param("history_json_path", typ.Any).
Returns(typ.Any, typ.NewOptional(typ.LuaError)).Build()},
})
Comment on lines +70 to +75
ctx := l.Context()

dcReg := temporalapi.GetDataConverterRegistry(ctx)
if dcReg == nil {
return invalidError(l, "temporal data converter registry not available in context")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants