variation on a theme: http file server with isolates

In which I try to mimic Erlang’s process supervision mechanism with Dart’s isolates (poorly).

From last time

Looking at the docs for Isolate it looks like I will need to refactor how I start the server. I’ll need a function outside of main to pass to Isolate.spawn so towards that goal I’m gonna experiment with simpler cases to get a feel for what spawning isolates exactly entails and how various isolates share information

That seems to work but I’m not sure why. I don’t understand the types and the control flow. I suspect I have a race condition and the main isolate will not wait for startServer to do its work. After adding a sleep call inside startServer my suspicions are verified. I need a way to wait on isolates but I don’t see any obvious ways to do that. There is something about SendPort and ReceivePort so gonna save this current thread and resume it when I understand how ports work.

Ports

In which I try to understand how ports work for sending and receiving messages between isolates (actually I just need to learn enough to know how to restart isolates for now)

The above works as I expect it to. The main thread blocks and the spawned isolate prints after 1 second. Still unclear why adding port.listen blocks the main thread, will probably need to read more of the docs to figure it out. In Erlang processes have links and when something bad happens linked processes are notified. I want to do the same thing here (or close enough to it anyway because Erlang links are bidrectional and that doesn’t seem to be the case here). The docs says something about error ports so lets see how that plays out

It kinds works. When the worker finishes I get null as the exit message but this is kinda annoying because it means I can’t distinguish between workers. Maybe this is not a big deal for the scheme I’m trying to cook up since I plan to have a uniform set of workers anyway. The docs say something about addOnExitListener with a caveat about starting things in paused state because it is possible for a spawned isolate to exit before the listener is attached. I don’t understand the inconsistency in the API but gonna go ahead anyway

Now I get the expected output. Each isolate has a unique identifier so I can do more clever things by tracking the identifiers but it’s more verbose than I’d like compared to the rest of the language. I will need to create a wrapper if I don’t want to get tripped up.

Let’s see what happens now when the worker throws an exception

I get the expected output for the error listener. I think I have enough to go back to my main thread now. Returning back to main thread…

Main Thread

I need to refactor things so I can start the server in an isolate. Simplest thing is a top-level method

I’ve removed the exception handling code because I want to test restarting the server with the error listener

This kinda works. It doesn’t quite do what I want when there is an error. The connection is left open on the client side. I don’t know if this means stuff is leaking or not because I would have expected unhandled exceptions in an isolate to clean up and finalize any resources associated with the isolate but that is not what happens. When I run with dart --observe=8081 --pause-isolates-on-exit=false --pause-isolates-on-unhandled-exceptions=false ... I can see that once the connection is closed a new isolate takes its place. Looks like isolates are not a panacea for avoiding exceptions entirely

Figuring out how to spawn several workers and do the same kind of restarting as for one worker is left as an exercise for the reader