Defer through a Fiber trampoline
Instead of running all defer blocks on the EM reactor fiber, run in a dedicated
Fiber trampoline. Inherit the trampoline from scope if present, or from the
promise you call #then on, or else make a new trampoline. This means that all
callbacks on promises in a logical chain run in the same Fiber as each other,
but a different one from all other code, so Fiber-local variables are scoped to
the logical chain, like so:
EMPromise.resolve(nil).then {
Thread.current[:fiber_local] = 123
promise_timer(1)
}.then {
p Thread.current[:fiber_local] # 123
}
This also allows us to mix promise-based and fiber-based code arbitrarily,
without any extra special helpers, including #sync itself, for example:
EMPromise.resolve(nil).then {
promise_timer(1).sync
DB.exec("SQL")
}