Promise lifecycle not documented
It is not clear whether a promise is cancelled and/or destroyed when all references to a promise (outside of the library's internals) go out of scope. I had presumed that underlying KJ promises were detached or wrapped into a kj::TaskSet because there does not seem to be any way to start background tasks in pycapnp and usually my "fire-and-forget" promises would still be resolved.
Below are three minimal reproductions that can be run inside an interactive interpreter to show that Promise chains do not resolve if the reference is dropped, though oddly only after a GC collection rather than immediately (implying that the refcount isn't zero).
Keep reference, run GC
import capnp
import gc
flag = False
def update_flag(_):
global flag
flag = True
promise = capnp.Promise(0).then(update_flag) # keep reference
gc.collect()
capnp.poll_once()
assert flag is True # pass
Drop reference, run GC
import capnp
import gc
flag = False
def update_flag(_):
global flag
flag = True
capnp.Promise(0).then(update_flag) # Drop reference
gc.collect() # Collect dropped reference
capnp.poll_once()
assert flag is True # fail
Drop reference, no GC
import capnp
flag = False
def update_flag(_):
global flag
flag = True
capnp.Promise(0).then(update_flag) # Drop reference
capnp.poll_once()
promise
assert flag is True # probably pass
Should a separate issue be raised to integrate kj::Promise::detach or kj::TaskSet into pycapnp (if I haven't missed something)?
Additionally, returning a promise chain (but not keeping our own reference) from an RPC (including ones returning void, i.e. -> ()) seems to temporarily transfer ownership and resolve before replying to the client caller.
If any of this matters:
- Ubuntu 20.04.1
- CPython 3.8.10
- pycapnp 1.1.0