sdzx-1
February 2, 2026, 9:15am
1
I’m studying the connect function in the latest Zig code, which is the same function Andrew introduced in Devlog’s Async DNS Resolution .
I’ve created a graph showing the relationships between the async functions:
I can roughly understand the dependencies between them, but I’m very confused about the error handling parts in the specific code.
what error handling parts are you confused by?
sdzx-1
February 2, 2026, 10:34am
3
pub fn connectMany(
host_name: HostName,
io: Io,
port: u16,
results: *Io.Queue(IpAddress.ConnectError!Stream),
options: IpAddress.ConnectOptions,
) LookupError!void {
defer results.close(io);
var canonical_name_buffer: [max_len]u8 = undefined;
var lookup_buffer: [32]HostName.LookupResult = undefined;
var lookup_queue: Io.Queue(LookupResult) = .init(&lookup_buffer);
var lookup_future = io.async(lookup, .{ host_name, io, &lookup_queue, .{
.port = port,
.canonical_name_buffer = &canonical_name_buffer,
} });
defer lookup_future.cancel(io) catch {};
//The cancellation here is executed later than the comment below.
var group: Io.Group = .init;
defer group.cancel(io);
while (lookup_queue.getOne(io)) |dns_result| switch (dns_result) {
.address => |address| group.async(io, enqueueConnection, .{ address, io, results, options }),
.canonical_name => continue,
} else |err| switch (err) {
error.Canceled => |e| return e,
//Therefore, shouldn't we not get error.Canceled here?
error.Closed => {
try group.await(io);
return lookup_future.await(io);
},
}
}
vulpesx
February 2, 2026, 10:42am
4
It can be cancelled by other things, e.g in connect once a connection is gotten from the queue, or even be cancelled by the caller of connect etc
sdzx-1
February 2, 2026, 10:52am
5
I understand now, the cancel operation here caused the getOne function to throw an error error.Canceled. Instead of getOne returning normally, the returned result is an error: error.Canceled.
connect_many.cancel(io) catch {};
sdzx-1
February 2, 2026, 10:53am
6
I got confused about the difference between these two.