Skip to content

Commit 83adb15

Browse files
committed
Unsplat state before checkpoint to capture parameters
Function parameters were not always getting captured in the state when checkpointing before a `try` block. Unsplatting right before checkpoint ensures that the variables stick around.
1 parent f9a4a90 commit 83adb15

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

lib/chorex.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,7 @@ defmodule Chorex do
576576
RuntimeMonitor.begin_checkpoint(state.config.monitor, barrier_token)
577577

578578
# send state to monitor
579+
unquote_splicing(unsplat_state(ctx))
579580
RuntimeMonitor.checkpoint_state(state.config.monitor, unquote(label), state)
580581

581582
# func frame so that we get the right return value

test/broken_recover_test.exs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
defmodule BrokenRecoverTest do
2+
use ExUnit.Case
3+
4+
import Chorex
5+
6+
defmodule HandyLogger do
7+
use GenServer
8+
9+
@impl true
10+
def init(_) do
11+
{:ok, []}
12+
end
13+
14+
@impl true
15+
def handle_info({:log, msg}, state) do
16+
{:noreply, [msg | state]}
17+
end
18+
19+
@impl true
20+
def handle_call(:flush, _from, state) do
21+
{:reply, state, []}
22+
end
23+
end
24+
25+
defmodule Recover3TestChor do
26+
defchor [Rec3Alice, Rec3Bob] do
27+
def run(Rec3Alice.(lgr), Rec3Bob.(lgr)) do
28+
try do
29+
Rec3Alice.f(1 / 0) ~> Rec3Bob.(y)
30+
rescue
31+
Rec3Alice.log_failure(lgr)
32+
Rec3Bob.log_failure(lgr)
33+
end
34+
Rec3Alice.(2 + 2) ~> Rec3Bob.(sum)
35+
Rec3Bob.(sum)
36+
end
37+
end
38+
end
39+
40+
defmodule MyRec3Alice do
41+
use Recover3TestChor.Chorex, :rec3alice
42+
43+
@impl true
44+
def f(a) do
45+
a
46+
end
47+
48+
@impl true
49+
def log_failure(logger) do
50+
send(logger, {:log, :failed})
51+
end
52+
end
53+
54+
defmodule MyRec3Bob do
55+
use Recover3TestChor.Chorex, :rec3bob
56+
57+
@impl true
58+
def log_failure(logger) do
59+
send(logger, {:log, :failed})
60+
end
61+
end
62+
63+
test "failure-path2 with continuation" do
64+
{:ok, l1} = GenServer.start(HandyLogger, nil)
65+
{:ok, l2} = GenServer.start(HandyLogger, nil)
66+
Logger.configure(level: :none) # suppress crash messages
67+
# Note: parameter different
68+
Chorex.start(Recover3TestChor.Chorex, %{Rec3Alice => MyRec3Alice, Rec3Bob => MyRec3Bob}, [l1, l2])
69+
70+
assert_receive {:chorex_return, Rec3Bob, 4}
71+
assert [:failed] = GenServer.call(l1, :flush)
72+
assert [:failed] = GenServer.call(l2, :flush)
73+
Logger.configure(level: :all)
74+
end
75+
end

0 commit comments

Comments
 (0)