We have some code that was working fine until we migrated to julia-1.10 and now with Julia 1.10.2 it’s quite flaky. I’ve reduced the code to the example below, which I think shouldn’t violate the assertion, but it does.
The absurd thing is it still kinda works in VScode REPL, but it’s flaky. When I run it in terminal REPL it breaks nearly 100% of the time.
Am I wrong in my expectation this should work? Is this a bug?
function repro()
taskref = Ref{Task}()
feedback = Channel(_ -> nothing; taskref)
wait(taskref[])
# isopen(feedback) && sleep(0.1)
@assert !isopen(feedback) # this fails unless the line above is uncommented
end
repro()
I’m trying this on Linux with julia 1.9.3 and 1.10.2
Yeah, with your demonstration it’s quite clear it’s a bug.
Also, to clarify, this is not a regression from 1.9 to 1.10, the reduced example breaks in both. For some reason, our original code works reliably in 1.9, and flaky in 1.10.
I came to conclusion that your suggestion to use wait(feedback) is the right way to handle the situation. It’s mildly annoying that wait(::Channel) throws, but that’s a separate discussion.
In principle you shouldn’t rely on isopen() telling you the “true” state, as in multitasking system, the state can change an instant later. So, you should be using fetch()/take!()/wait(::Channel) are more reliable.
It looks like there’s no special magic behind bind(ch::Channel, t::Task). Effectively it does @async begin ; wait(t) ; close(ch); end + some exception handling. So @assert !isopen(feedback) may or may not fail depending on how exactly tasks get scheduled. This probably explains why our original code got flaky on 1.10, it wasn’t robust to start with.