Easier API for cross-loop. usage
Today in RediStack most APIs are thread-safe, making it possible to use the various types from across different event loops. This is great, it reduces the risk of awkward bugs.
However, the thread-safety hides a nasty sharp edge, which is that the various
EventLoopFutures returned from the various APIs are bound to the event loop of the connection (or pool), not the event loop the user may be on. This means that in highly concurrent programs (such as Vapor applications) that use a bunch of different event loops, it is surprisingly easy for users to fail to notice that their
.flatMap calls will execute on an event loop that is different from the one the calling code was on.
This can lead to subtle thread-safety bugs. The only way out of these bugs in the current design is for users to apply
.hop(to:) calls on any call to RediStack. This applies a cognitive burden to the user, who needs to constantly be defensive whenever they see a call to RediStack. This goes double if the actual call to RediStack is deep in an API, such that the user may not see it at all.
We should take on the
hop(to:) burden for the user. This can be done by amending all the RediStack query entry points that currently return an
EventLoopFuture to also take an
EventLoop argument. This argument will be combined with a call to
hop(to:) at the top-level, just as we return to user code. This will automatically handle the possibility that the user wanted to be called on a different
EventLoop than the one we want to execute on.
This needs to be done as part of 2.0 work as it requires changing every public API entry point. We could in principle do it without an API break, but if you were planning one anyway it's not a bad idea to add this.
Wait for async/await, which would also fix this issue. However, I don't think that's a good idea: we're seeing real bugs caused by this issue today, and it would be good to defend against it.