From e207f535ee47304ae2423a4a8b7a5f8203e684f8 Mon Sep 17 00:00:00 2001 From: sotashimozono Date: Fri, 25 Sep 2026 05:08:21 +0000 Subject: [PATCH] Raise the stop flag after the first key, not after 50 ms (0.6.7) The test assumed `run!` starts within 50 ms. With DataVault 0.8.7 a run-start observation keeps the packages the process loaded, which takes most of a second, so the timer fired before any key ran and `result.done >= 1` failed (0 >= 1), both on DataVault#58's downstream job and locally. The old test was run against 0.8.7 here and fails the same way; this one passes. The flag is still raised by a concurrent task, now once the first key has finished, so the test says the same thing without a clock. Co-Authored-By: Claude Opus 5.5 (1M context) --- Project.toml | 2 +- test/run/test_run_adversarial.jl | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index d50e3be..f6afbd4 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "SweepRunner" uuid = "be946ad2-3cb3-4b6e-8f7e-4a5ecc3c255b" -version = "0.6.6" +version = "0.6.7" authors = ["sota shimozono "] [deps] diff --git a/test/run/test_run_adversarial.jl b/test/run/test_run_adversarial.jl index acff541..3d20963 100644 --- a/test/run/test_run_adversarial.jl +++ b/test/run/test_run_adversarial.jl @@ -38,19 +38,30 @@ allk_a(v) = ParamIO.expand(v.spec) @test length(keys) >= 4 stop = joinpath(outdir, "STOP_NOW") - # Delay the stop flag by 50 ms so a few keys finish first - t = Timer(_ -> touch(stop), 0.05) + # The concurrent task raises the flag once the first key has finished — not after a fixed + # delay, which assumed `run!` starts within it. It does not always: a run-start + # observation that keeps the packages the process loaded takes most of a second, and a + # 50 ms timer then fired before any key ran. + first_done = Channel{Nothing}(1) + raiser = @async try + take!(first_done) + touch(stop) + catch e + e isa InvalidStateException || rethrow() # closed: the run ended first + end - # work_fn sleeps so we're sure the stop is seen after some work + # work_fn sleeps so the raiser gets to run while keys remain counter = Ref(0) work_fn = k -> begin counter[] += 1 sleep(0.02) + counter[] == 1 && put!(first_done, nothing) Dict{String,Any}("x" => 1) end result = run!(work_fn, v, keys; opts=RunOpts(stop_flag=stop)) - close(t) + close(first_done) + wait(raiser) # At least one key ran before stop kicked in, at least one was skipped @test result.done >= 1