mirai
mirai copied to clipboard
Support for mirai cancellation
Hi Charlie, while it was on my mind, I just wanted to jot down some thoughts regarding cancellation, in case it's a feature you're ever interested in pursuing (which would definitely be great for Shiny btw). Probably a lot of the below is not news to you, hope I don't offend you by stating what might be obvious to you--these are just my thoughts.
There are several parts to cancellation: 1) how you invoke it, 2) how it cancels the task, 3) how/when it's reported back to the controlling process.
Invocation
The obvious would be mirai$cancel()
. The alternative is to use a cancellation token, where each mirai needs to be handed a cancellation-signaling object during construction. For starting/cancelling a single task, the cancel() method is easier; but for coordinating lots of tasks that are logically part of a single operation, the cancellation token approach is easier.
It might be more convenient to have with(cancellationToken, { ... })
, i.e. the ability to install a default global cancellation token.
Cancellation
It's either cooperative (make the user's mirai expression explicitly check for interruption) or non-cooperative (send SIGINT/Ctrl+C). For R, probably the vast majority of the time, non-cooperative is fine? But it seems wrong not to make cooperative possible (or at least the ability for the user to say "during this critical section, don't let me be interrupted").
I guess the "pick reasonable defaults" approach would be for it to be non-cooperative by default and then have a way to override the default behavior to ask for cooperative instead. While the "be explicit" approach would be to not support cancellation unless the mirai()
function is explicitly told whether the code is designed for cooperative cancellation, or ready for non-cooperative interruption.
Reporting back
Cancellation could be fire-and-forget (the mirai object acts as if interruption succeeded immediately, even if the task is still actually running), like posix signals.
Or it could join on the task, so the user can know whether it was actually interrupted or if it ran to completion before it had a chance to be interrupted. You could imagine the latter distinction mattering for side-effecty operations--like if you tried to cancel a bank transfer, it's important to know whether the cancellation succeeded. I personally have found in practice this seems to almost never matter--or at least, it's nice to know if the task has actually stopped but the distinction between "it stopped because you asked it to" vs. "it stopped on its own" rarely matters; in the bank transfer example you'd probably want to do a query to determine whether it succeeded or not, anyway.