`ev/select` still revives fibers....
amano-kenji opened this issue · 3 comments
In production code, when ev/select
is called again, It even runs defer
forms after they are run once...... They shouldn't be run again.... Because of this issue, I eliminated channel/from-each
and ev/select
in my production code.
This is my minimal example.
(import spork/stream)
(import spork/sh)
(import spork/channel)
(def chan (ev/chan))
(defn revive-fibers
[]
(def /dev/null (sh/devnull))
(defer (do
(:close /dev/null)
(eprint "/dev/null closed"))
(def proc (os/spawn ["sleep" "10000000000"]
:p {:out :pipe :err /dev/null}))
(defer (do
(:close proc)
(eprint "proc closed"))
(def lines (channel/from-each (stream/lines (proc :out))))
(ev/spawn
(ev/sleep 2)
(:kill proc false :term))
(match (ev/select chan lines)
[:close c]
(eprint "lines closed naturally")))))
(def supervisor (ev/chan))
(ev/spawn
(forever
(let [[status fiber] (ev/take supervisor)]
(eprintf "status: %n, fiber: %n, fiber/last-value: %n" status fiber
(fiber/last-value fiber)))))
(ev/go revive-fibers nil supervisor)
Output is
status: :ok, fiber: <fiber 0x55CFED05D6C0>, fiber/last-value: <core/process 0x55CFED0595F0>
status: :ok, fiber: <fiber 0x55CFED05D010>, fiber/last-value: nil
lines closed naturally
status: :ok, fiber: <fiber 0x55CFED05D340>, fiber/last-value: nil
status: :error, fiber: <fiber 0x55CFED05D340>, fiber/last-value: nil
proc closed
/dev/null closed
status: :ok, fiber: <fiber 0x55CFED05CB10>, fiber/last-value: nil
I noticed that the iterable task of channel/from-each
was not really cancelled because ev/select
didn't return a value in channel/from-each
.
Hard to say for certain yet (I'm looking into this) but I think the issue is with channel/from-each
looking for specific errors and then calling propagate.
I'm thinking that I'm using ev/select
wrong. In the above example, ev/select
is called twice on the same channel.
So on latest master, this seems to work as expected (as I expected). I wrapped every call to ev/go
and ev/spawn
with tracev
so we can see which fibers are created, and then added this bit of code to monitor which fibers are active:
(forever
(ev/sleep 1)
(def all-tasks (ev/all-tasks))
(def me (fiber/root))
(def sans-self (seq [t :in all-tasks :when (not= me t)] t))
(printf "%n" sans-self))
At the end, a single fiber is left running that corresponds to the loop that is reading from the supervisor channel via (ev/spawn (forever ...))
Closing as cannot reproduce, please reopen if still an issue.