# Discussion: "Timeouts and cancellation for humans"

**URL:** <https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26>\
**Category:** Structured concurrency\
**Created:** [February 6, 2019, 8:40pm UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26 "2019-02-06T20:40:26Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![njs](https://yyz2.discourse-cdn.com/free1/user_avatar/trio.discourse.group/njs/32/11_2.png) [@njs](https://trio.discourse.group/u/njs)\
**Post date:** [February 6, 2019, 8:40pm UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26/1 "2019-02-06T20:40:26Z")

</div>

You can use this thread to discuss the blog post [Timeouts and cancellation for humans](https://vorpus.org/blog/timeouts-and-cancellation-for-humans/).

---

<div class="post-metadata">

**Author:** ![dlukes](https://yyz2.discourse-cdn.com/free1/user_avatar/trio.discourse.group/dlukes/32/192_2.png) [@dlukes](https://trio.discourse.group/u/dlukes)\
**Post date:** [January 23, 2020, 11:46am UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26/2 "2020-01-23T11:46:23Z")

</div>

> So `requests` doesn’t have to do anything to pass this through – when it eventually sends and receives data over the network, those primitive calls will automatically have the deadline applied.

Just to be clear – this refers to a hypothetical `requests` library with support for async and trio in particular (as implemented e.g. by `asks`), not the **actual** `requests` library, right? I tried running `requests.get` on a slow responding server inside a `with trio.move_on_after(...)` block, and `trio`’s timeout was not applied.

Not complaining, just making sure I understand this correctly – if it worked without any effort required from third-party library developers, it would be downright magical 🙂

As an aside, thank you so much for all your posts related to async, as well as the `trio` docs! Your writing is top-notch, you manage to keep it accessible yet technically detailed, a rare ability 🙂

---

<div class="post-metadata">

**Author:** ![dlukes](https://yyz2.discourse-cdn.com/free1/user_avatar/trio.discourse.group/dlukes/32/192_2.png) [@dlukes](https://trio.discourse.group/u/dlukes)\
**Post date:** [January 23, 2020, 12:05pm UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26/3 "2020-01-23T12:05:58Z")

</div>

Never mind, I should have finished reading the article before starting to experiment and asking questions 🙂 The **Summary** section makes it pretty clear that `requests` indeed needs to be ported over to async + trio before the sample timeout code can work.

---

<div class="post-metadata">

**Author:** ![abigailct](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@abigailct](https://trio.discourse.group/u/abigailct)\
**Post date:** [January 25, 2020, 7:09pm UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26/4 "2020-01-25T19:09:38Z")

</div>

I’m guessing the timing on the Cancel tokens described here won’t be perfectly exact - it’ll take some (small) amount of time to call `after`, such that `time.monotonic` is slightly late.

Assuming that’s the case, would this timing error compound with repeated calls to `after`?  
If not, why?, and if so, could the Cancel token structure be changed to fix this?

I’m guessing this isn’t super important for most of trio’s applications, but I was curious about it anyway - I’ve seen a similar construct in Ada where non-compounding timing errors matter a lot.

---

<div class="post-metadata">

**Author:** ![njs](https://yyz2.discourse-cdn.com/free1/user_avatar/trio.discourse.group/njs/32/11_2.png) [@njs](https://trio.discourse.group/u/njs)\
**Post date:** [January 26, 2020, 1:04am UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26/5 "2020-01-26T01:04:17Z")

</div>

Trio lets you set timeouts as either relative or absolute times, and it always stores them internally as absolute times. For example, `move_on_after(10)` is just a convenient shorthand for `move_on_at(trio.current_time() + 10)`, and `sleep(10)` is a shorthand for `sleep_until(trio.current_time() + 10)`. So if you’re in a situation where you want to e.g. set a timer for every 10 seconds, you can do that by using the absolute time API: `sleep_until(start_time + i*10)`.

---

<div class="post-metadata">

**Author:** ![refi64](https://yyz2.discourse-cdn.com/free1/user_avatar/trio.discourse.group/refi64/32/205_2.png) [@refi64](https://trio.discourse.group/u/refi64)\
**Post date:** [March 21, 2020, 5:20am UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26/6 "2020-03-21T05:20:15Z")

</div>

I just now stumbled upon this post and absolutely loved it (as well as Trio’s overall nursery idea). I was curious of you had ever heard of GLib’s [GCancellable](https://developer.gnome.org/gio/stable/GCancellable.html), which is sort of like cancel tokens, except a lot more primitive with less sugar (because C).

---

<div class="post-metadata">

**Author:** ![belm0](https://yyz2.discourse-cdn.com/free1/user_avatar/trio.discourse.group/belm0/32/69_2.png) [@belm0](https://trio.discourse.group/u/belm0)\
**Post date:** [September 24, 2022, 1:05am UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26/7 "2022-09-24T01:05:56Z")

</div>

I’ve read this article a few times over the years, and will try to sum up the high-level implications:

- njs lays out a better programming mechanism for timeouts and cancellation (arguably, setting a new state-of-the-art)
- for the case of concurrent programs, the solution relies on structured concurrency
- in the domain of “making concurrency manageable”, the solution likely represents the first must-have feature built on top of structured concurrency
- it’s reiterating the strength of structured concurrency: that the paradigm allows programming solutions (in the form of API, language control structure, etc.) that work for non-concurrent programs to be applied equally to concurrent programs

What I’m still curious about: was the article and associated Trio implementation the first time that cancellation was done this way (on top of structured concurrency)? I’m not familiar with Kotlin’s cancellation API, and wonder if @elizarov could comment on whether it was based on Nathaniel’s work.

---

<div class="post-metadata">

**Author:** ![Positron](https://yyz2.discourse-cdn.com/free1/user_avatar/trio.discourse.group/positron/32/374_2.png) [@Positron](https://trio.discourse.group/u/Positron)\
**Post date:** [July 11, 2024, 9:49am UTC](https://trio.discourse.group/t/discussion-timeouts-and-cancellation-for-humans/26/8 "2024-07-11T09:49:23Z")

</div>

Reading this article for a second time, and I have a remark:

```auto
def send_websocket_messages(url, messages, cancel_token):
    open_websocket_connection(url, cancel_token=cancel_token)
    try:
        for message in messages:
            ws.send_message(message, cancel_token=cancel_token)
    finally:
        ws.close(cancel_token=cancel_token)

```

> Once the cancel token is triggered, then all future operations on that token are cancelled, so the call to ws.close doesn’t get stuck. It’s a less error-prone paradigm.

Except that this only works well in case of network error, but if the user clicks “Abort” button, we still want to gracefully close the socket, i.e. to run `ws.close()` normally. Here the cancel token works like an emergency fire suppression system - it sucks air from the building and doesn’t care for normal procedures. Even when some cancellations should perform normal procedures. Like the author said, it’s difficult.
