# "Timeouts and cancellation for humans"

**URL:** <https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575>\
**Category:** Media\
**Created:** [September 12, 2026, 12:55am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575 "2026-09-12T00:55:31Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![smj-edison](https://ziggit.dev/user_avatar/ziggit.dev/smj-edison/32/6629_2.png) [@smj-edison](https://ziggit.dev/u/smj-edison)\
**Post date:** [September 12, 2026, 12:55am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/1 "2026-09-12T00:55:31Z")

</div>

I just read this interesting discussion of cancelation using “cancelation tokens”: [Timeouts and cancellation for humans — njs blog](https://vorpus.org/blog/timeouts-and-cancellation-for-humans/)

I don’t think it’s as applicable to Zig, since supposedly any timeout code in Zig would be based on a task that had one job, mainly to return error.Canceled after a fixed period of time, but it’s still an interesting approach.

---

<div class="post-metadata">

**Author:** ![lalinsky](https://ziggit.dev/user_avatar/ziggit.dev/lalinsky/32/3720_2.png) [@lalinsky](https://ziggit.dev/u/lalinsky)\
**Post date:** [September 12, 2026, 3:37am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/2 "2026-09-12T03:37:59Z")

</div>

Zio, which was very much influenced by Trio, has a similar concept of cancel scopes, but obviously it uses `defer` instead of context managers. It’s an extremely powerful concept, where you need to enforce timeouts to larger chunks of code. In `std.Io`, you can kind of emulate it with two concurrent tasks, one running your code, one `futexWait`-ing on a variable that controls the timeout and cancelling the task if it expires.

```zig
var timeout: zio.AutoCancel = .init;
defer timeout.clear();

timeout.set(.fromSeconds(60));

handleRequest(...) catch |err| switch (err) {
    error.Canceled => |e| return if (timeout.check(e)) error.RequestTimeout else e,
    else => |e| return e,
};

```

You can read more about it here: [Timeouts in zio | Lukáš Lalinský](https://lalinsky.com/2026/06/04/timeouts-in-zio.html)

---

<div class="post-metadata">

**Author:** ![psznm](https://ziggit.dev/user_avatar/ziggit.dev/psznm/32/8377_2.png) [@psznm](https://ziggit.dev/u/psznm)\
**Post date:** [September 12, 2026, 6:43am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/3 "2026-09-12T06:43:11Z")

</div>

I have implemented timeouting recently. I went with approach of one task awaitTimeouting on Io.Event per connection for which one timeout at a time works fine. But I am not completely happy with that because it takes additional fiber per connection, so I think I will be moving to timer wheel per OS thread which should reduce overhead alot.

But later I also want much shorter timeout on tcp read/write that wont be cancelling the whole connection so that I can demote buffer sizes on inactive connections. This is currently an issue because the read/write cannot be cancelled individually without wrapping it in its own task which would again introduce alot of overhead. But I _think_ zig 0.17 and netRead/netWrite becoming an operation may help me solve the issue efficiently, even though it will be alot more complex.

---

<div class="post-metadata">

**Author:** ![lalinsky](https://ziggit.dev/user_avatar/ziggit.dev/lalinsky/32/3720_2.png) [@lalinsky](https://ziggit.dev/u/lalinsky)\
**Post date:** [September 12, 2026, 9:29am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/4 "2026-09-12T09:29:52Z")

</div>

> [@psznm](#):
>
> But I _think_ zig 0.17 and netRead/netWrite becoming an operation may help me solve the issue efficiently, even though it will be alot more complex.

Yes, that’s correct. You can use both with `operateTimeout` in Zig 0.17, which gives you the short per op timeouts. There is another open PR to integrate this into reader/writer

---

<div class="post-metadata">

**Author:** ![lalinsky](https://ziggit.dev/user_avatar/ziggit.dev/lalinsky/32/3720_2.png) [@lalinsky](https://ziggit.dev/u/lalinsky)\
**Post date:** [September 12, 2026, 9:34am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/5 "2026-09-12T09:34:58Z")

</div>

> [@psznm](#):
>
> so I think I will be moving to timer wheel per OS thread which should reduce overhead alot.

This has another set of complications. You can only wait on task from one thread, and there is no way to cancel task without waiting for it to finish. That also means if you have one task that refuses to cancel (the error being swallowed, for example), then the entire timer thread is blocked. The only way to solve it is unfortunately another `group.concurent` per each `cancel`.

---

<div class="post-metadata">

**Author:** ![IbrahimOuhamou](https://ziggit.dev/user_avatar/ziggit.dev/ibrahimouhamou/32/2344_2.png) [@IbrahimOuhamou](https://ziggit.dev/u/IbrahimOuhamou)\
**Post date:** [September 13, 2026, 12:06am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/6 "2026-09-13T00:06:40Z")

</div>

will Io.reader have timeouts or just the implementations? maybe something like `io.concurrent` which accepts an io param and can return the error `TimeOutUnavailable`

---

<div class="post-metadata">

**Author:** ![xeondev](https://ziggit.dev/user_avatar/ziggit.dev/xeondev/32/9912_2.png) [@xeondev](https://ziggit.dev/u/xeondev)\
**Post date:** [September 13, 2026, 9:29am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/7 "2026-09-13T09:29:15Z")

</div>

`std.Io.operateTimeout` leaks the `Batch` and all the pending operations though. Buggy implementation sneaked in likely due to it being fine with `Threaded` on POSIX. It’s already broken in case of e.g. `file_read_streaming` on Windows, because nothing will get canceled after `operateTimeout` exits. I’ve opened a PR for this, but it got CI failures due to another bug in `Threaded` xD

---

<div class="post-metadata">

**Author:** ![xeondev](https://ziggit.dev/user_avatar/ziggit.dev/xeondev/32/9912_2.png) [@xeondev](https://ziggit.dev/u/xeondev)\
**Post date:** [September 13, 2026, 9:32am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/8 "2026-09-13T09:32:29Z")

</div>

It’s really desirable to avoid spawning another `io.concurrent` just for the sake of waiting on a timer. Therefore, it’s better to couple the timeout functionality with a concrete implementation. For example, one for `net.Stream.Reader` would lower to using `Batch.awaitConcurrent`.

At the same time, nobody really stops you from implementing a `Reader` that wraps another `Reader` and just slaps timeouts on top via `io.concurrent`.

---

<div class="post-metadata">

**Author:** ![smj-edison](https://ziggit.dev/user_avatar/ziggit.dev/smj-edison/32/6629_2.png) [@smj-edison](https://ziggit.dev/u/smj-edison)\
**Post date:** [September 15, 2026, 11:50pm UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/9 "2026-09-15T23:50:38Z")

</div>

Agreed that spinning up a whole task just for a timeout is a waste, but I don’t think the solution is to go back to per-op timeouts either. I think the point of this article is that a timeout should be the total time waited, not how long each op waits, because otherwise it leaks implementation details.

---

<div class="post-metadata">

**Author:** ![lalinsky](https://ziggit.dev/user_avatar/ziggit.dev/lalinsky/32/3720_2.png) [@lalinsky](https://ziggit.dev/u/lalinsky)\
**Post date:** [September 16, 2026, 4:55am UTC](https://ziggit.dev/t/timeouts-and-cancellation-for-humans/17575/10 "2026-09-16T04:55:54Z")

</div>

This is the best `std.Io` can have:

[https://codeberg.org/ziglang/zig/issues/31098](https://codeberg.org/ziglang/zig/issues/31098)

For anything more, the API needs to be aware of the running task, so that rules out `std.Io`, at least in the current form. If we had an API to get the current task from within the task, and non-blocking cancellation, it would be possible to express it. For now, these kind of timeouts around a block of code only can be done within an async runtime, that’s why zio has them.
