Hi!
We ran into a surprising corner-case where if a deferred chain has a manifold from alia (from alia.manifold/execute) in the chain, the subsequent fns in the chain will be executed on the cassandra java-driver pool, not the manifold pool
d/chain' avoids this behavior
but it's a bit unclear right now how we could keep the benefits of d/chain while avoiding this behavior (which can quickly exhaust the small I/O callback pools used by cassandra-driver)
if I recall you can pass an :executor option to alia.manifold/execute to have the callback run in another pool
that could be a way to temporarly mitigate the issue
I'll try that
it still boggles me
I can track that down to (d/on-realized (alia.manifold/execute ...) #(warn %) #(warn %)) as showing the callback running on the cassandra-driver netty threadpool
I don't get how on-realized manages to schedule the callbacks on netty's threadpool
(the result is a ListenableFuture which extends Future which manifold considers as a valid deferred)
I'd have to check how things work internally in manifold, I am not too familiar with it.
but I'm not seeing where the execution is directed to the threadpool
huh, i'm surprised i've never run in to that problem
what made you notice it @pyr?
in alia we have the callback (guava future) run in execute currentThread, unless specified otherwise.
that's how I remember it at least (so from where execute was called from in short)
@mccraigmccraig exhausting cassandra-driver's pool
specifiying the executor in query opts obviously fixes the issue
I'm still surprised
since d/chain' doesn't expose the behavior
weird
does the cassandra-driver pool throw when it's exhausted ?
Do you think alia should by default expose/use a callback threadpool to avoid these kind of odd cases?
not necessarily
the standard cassandra-driver threadpool is quite valid for I/O callbacks
If I recall I followed what java-driver does, not creating an additional pool for this and leaving it to the user
and no cpu should happen there
but I ll revisit that
yeah
exactly
so I think this is valid
at some point the result is picked up as homomorphic to a deferred (makes sense) but the listenablefuture's callback pool is then used as the executor (doesn't yet make sense to me :-))
I'll dig further and use :executor in the meantime
I get highlights/notifications on "alia" mentions, looking fwd to understanding what's up
Ok, it seems to come down to this:
alia creates a deferred w/o specifying an executor in alia.manifold/execute
When d/success! or d/error! are called
The corresponding deferred thus has no executor, which means that the callbacks will be executed on the calling thread, hence in this case on cassandra-driver's threadpool
oh right, so in theory just passing the :executor option value to deferred should do it, then the alia/execute calling thread would be the default and the user can overwrite that with that :executor option if needed
ah wait no
deferred with no args gets (ex/executor)
my theory is wrong
hmm
sorry
right: https://github.com/ztellman/manifold/blob/master/src/manifold/deferred.clj#L562
this is it though
ex/executor yields nil in my case
https://github.com/ztellman/manifold/blob/master/src/manifold/executor.clj#L24-L25
OK, so I can wrap alia.manifold/execute in a manifold.executor/with-executor and all is well
sorry about the noise
no worries, good to know.
(this keeps compute-bound in the manifold pool, and I/O in the cassandra-driver pool)