The below will raise FutureDefect and thus exit the program without being caught and executing echo "Done normally"
import chronos
proc asyncProc() {.async.} =
await sleepAsync(10)
raise newException(ValueError, "Bad stuff")
proc someProc() =
asyncCheck asyncProc()
someProc()
try:
runForever()
except CatchableError as e:
echo "Caught a catchable error"
echo "Done normally"
I would like to be able to catch ValueError (or an exception containing it) outside of asyncProc, as "normal" errors such as this do not represent a sufficiently erroneous case to crash the thread to me.
However, Chronos escalating the ValueError to a Defect means I cannot do so (unless I catch Exception which is meh for obvious reasons).
I've been playing around with chronos as part of a multithreading library that I am writing (built on top of taskpools).
What I would like to enable is essentially a server running on a single thread with its own while loop.
The loop essentially consists of:
That looks roughly like this:
proc processMessages(server: ServerActor) =
... loads of code ...
for msg in mailbox.messages:
process(msg) # <-- User defined proc! May call an async-proc via: asyncCheck anAsyncProc()
proc runServerLoop(server: ServerActor) {.gcsafe.} =
block serverLoop:
while isRunning():
{.gcsafe}:
try:
if not server.hasMessages():
server.waitForSendSignal() # This here includes a call to waitFor aThreadSignalPtr.wait() where it will execute async-work potentially created by processMessages
server.processMessages()
except CatchableError as e: # This should catch **any** exception casued by message-processing, including if thrown in async-block when running `waitForSendSignal`
error "Message caused exception", error = e[]
Users may define process procs to handle individual message types. I would like to basically save my users from themselves if possible. If their process proc throws an Exception and they do not deal with it, then I want globally deal with it (essentially catch it, log it and throw it away). I do not want it to bring the entire Thread down as it currently happens due to FutureDefect.
So my question is: For these kinds of "Global error-catching mechanisms" that I want - What is the ideal/intended way to do those? Is it maybe even impossible because of UB?
Note: I have read the error docs but they seem more directed at end-users that can control if any of their procs throw an exception. I could only do that here if I waitFor any asyncProc used within processMessages. This I would like to avoid for convenience reasons - I can provide decent default behavior for an exception so that users aren't forced to deal with their exceptions if they don't want to.
The answer after chatting with arne about it in the corresponding github issue (https://forum.nim-lang.org/t/11501#74701) : You don't catch them.
If waitFor ing somewhere triggers an exception (aka the event-loop being worked through triggers an exception) then you're risking resource leakage and generally having your application in an inconsistent state, which is defect worthy. It follows that you must ensure you don't throw errors in procs that you asyncCheck.