Is it possible for Zig's Io interface to queue up work that doesn't need to be awaited/canceled?

I just want to start off by saying that it’s very likely that I’m missing something here, whether it’s something in the code or something in the stated goals/design of the Io interface. It’s possible that I’m trying to shoehorn in a use-case that is not intended for the interface to cover, but it feels like this is something it should be capable of handling.

Basically, I want to be able to queue up some work that needs to be done in the background, but I don’t want to have to await or cancel (which the docs states should be equivalent to await with some added behavior) because doing so would “block” my execution until the Future is resolved. What I would like to do here is effectively spawn an async/concurrent unit of work that I can tell the Io to finish executing and then clean it up; that I don’t care about the result of the Future.

An example of this would be handling network connections. I would like to be able to spawn an async/concurrent unit to handle a connection without having to either “block” my execution on an await/cancel call or be forced to leak the any_future. It seems like there should be something that works similar to a std.Thread’s detach function.

My motivation here is to basically use the Evented Io or build my own Io implementation so that I can create “green threads” for handling my network connections rather than full OS threads.

Is this possible with the current Io design? Would the design need to be amended? Am I just trying to force a square peg into a round hole?

Thank you in advance for any advice/answers!

This is what Io.Group is for. If you want it to be detached, then use a process-wide Group that you initialize in main. You probably want to wait for it to finish before exiting the program, right?

// near the beginning of main after you init your Io
var group: Io.Group = .init;
defer group.cancel(io);

// your application code

This makes it so that you application finishes, you send a cancel request to your detached stuff (and then still wait for them to complete).

If you don’t want to wait for tasks in the group to complete you can call std.process.exit.

If you don’t want to send the cancel request, call try group.wait(io) after your application code. This way the cancel request happens only when an error occurs.

6 Likes

That’s exactly what I needed, thank you!

To illustrate why you still want to have “detached” tasks belong to a group, imagine that you are gracefully shutting down your server. You want to stop accepting new connections, while still finishing up the ongoing ones.

In this case, when you receive the event that a graceful shutdown has been initiated, you still want to wait for those existing tasks to finish, so that’s why you need a group. You could even do something like, after 10s if the tasks are not finished, request cancelation. This then gives a chance for the server to respond to clients with a message like “server is shutting down now, please reconnect” while interrupting any work that they are in the middle of doing.

7 Likes