# Warning when calling a blocking function in an async context

**URL:** <https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440>\
**Category:** Uncategorized\
**Created:** [December 6, 2019, 12:33pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440 "2019-12-06T12:33:01Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [December 6, 2019, 12:33pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/1 "2019-12-06T12:33:02Z")

</div>

A common issue users are having with async code is calling blocking functions inside of async contexts and being surprised that they block.

While we can't perfectly solve this problem, it would be fairly straightforward to have a heuristic lint.

First, it would require a new attribute similar to `#[must_use]`, let's say `#[might_block]`. This would only apply to function/method items. We'd apply this to every function in std which we consider to be "blocking" (because it performs blocking IO or blocks the thread for synchronization), and we'd make it available on stable for people to apply to their own functions.

Then, if the user calls a function tagged might\_block from inside an async context, we issue a warning them that this might block. This warning could be supressed, made into an error, etc.

As a more extreme solution (possibly a second step), we could make this attribute _transitive_, so any function which calls a might\_block function is also might\_block, unless its been tagged that it shouldn't be considered blocking for whatever reason (e.g. `#[allow(might_block)]`).

The attribute could also have an option for specifying a nonblocking alternative, though for std of course there are no nonblocking alternatives available in std.

---

<div class="post-metadata">

**Author:** ![spacekookie](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/spacekookie/32/6426_2.png) [@spacekookie](https://internals.rust-lang.org/u/spacekookie)\
**Post date:** [December 6, 2019, 12:42pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/2 "2019-12-06T12:42:08Z")

</div>

> [@withoutboats](#):
>
> The attribute could also have an option for specifying a nonblocking alternative, though for std of course there are no nonblocking alternatives available in std.

I guess it's not really feasible to make the output of a suggestion dependent on whether someone has async-std as a dependency, then suggesting the appropriate async-std function, if it exists?

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [December 6, 2019, 12:45pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/3 "2019-12-06T12:45:50Z")

</div>

> [@spacekookie](#):
>
> I guess it's not really feasible to make the output of a suggestion dependent on whether someone has async-std as a dependency, then suggesting the appropriate async-std function, if it exists?

We don't integrate that tightly with unofficial crates that the Rust project doesn't maintain (or pick favorites: even though async-std's APIs are more direct parallels to std's, tokio provides the same functionality).

EDIT: We could have some hook for dependencies to inject their own APIs into these lints (eg the suggestion would come from async-std or tokio directly), but that's getting very complicated and definitely out of scope for an MVP.

---

<div class="post-metadata">

**Author:** ![spacekookie](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/spacekookie/32/6426_2.png) [@spacekookie](https://internals.rust-lang.org/u/spacekookie)\
**Post date:** [December 6, 2019, 12:56pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/4 "2019-12-06T12:56:24Z")

</div>

> [@withoutboats](#):
>
> EDIT: We could have some hook for dependencies to inject their own APIs into these lints (eg the suggestion would come from async-std or tokio directly), but that's getting very complicated and definitely out of scope for an MVP.

Yea, that makes sense. This proposal sounds really cool, but definitely out of scope for now 😉

---

<div class="post-metadata">

**Author:** ![Migi](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/migi/32/4798_2.png) [@Migi](https://internals.rust-lang.org/u/Migi)\
**Post date:** [December 6, 2019, 2:24pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/5 "2019-12-06T14:24:56Z")

</div>

I'm in favor of an attribute like this. Using a blocking function inside an `async` context is a very inconspicuous error. Blocking functions are very common both in the standard library and in the whole ecosystem. Using them in an `async` context compiles without warnings, it passes all your tests, it even runs fine in production as long as you don't actually stress the system. You could write an http server with blocking code in its `async` functions that runs fine for months until one day you get a traffic spike and only then performance falls off a cliff.

And even then, you might have a very hard time finding that the root cause of your poor performance is that you used some blocking functions somewhere in your entire application. It might not even be you who does the blocking, it could happen in some unexpected place in a library somewhere. And even if you suspect blocking calls to be the issue, finding these blocking calls doesn't sound easy either.

It is really the worst kind of error: easy to make, hard to detect (both in the code and at runtime), and hard to debug, so an attribute like `#[might_block]` would be very useful. It makes the error harder to make and easier to detect. This attribute will never be able to catch all mistakes without changes to the type system (e.g. `Option::map` should be `#[might_block]` if and only if its argument is `#[might_block]`), but it's good enough even if we just catch _some_ of the mistakes, both as a teaching tool for new users who might not be aware of this issue, and as an extra line of defense against slip ups by experienced users.

I agree that `#[might_block]` should theoretically be transitive, in the sense that using a `#[might_block]` function inside another function (not marked `#[might_block]`) should give a warning that you should also mark that function `#[might_block]`. But from a practical point of view, I'm not so sure, because that would create lots and lots of warnings, nagging people to mark functions as `#[might_block]` even though they were never intended to be used in an `async` context. Perhaps this transitive warning should only be applied to `pub` functions in libraries. _(EDIT: maybe this transitive warning should just be a clippy lint?)_

I'm also not sure how pedantically `#[might_block]` should be applied to functions that can _technically_ block but rarely do. As mentioned in [this blog post](https://stjepang.github.io/2019/12/04/blocking-inside-async-code.html), even `println!()` can technically block, but the times where that will actually cause an issue seem to be extremely rare. I think adding `#[might_block]` to `println!()` would _not_ be a good idea.

---

<div class="post-metadata">

**Author:** ![CryZe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cryze/32/1653_2.png) [@CryZe](https://internals.rust-lang.org/u/CryZe)\
**Post date:** [December 6, 2019, 2:25pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/6 "2019-12-06T14:25:38Z")

</div>

What I've run into recently was that I accidentally had a parking\_lot::MutexGuard across an .await and it caused a deadlock (or actually panic because this was in wasm). An idea that I had would be that blocking guard-like data structures could be annotated with

```rust
#[cant_yield]
struct MutexGuard<T> { ... }

```

which would error out / warn if a value of such a type ends up in the backing generator states of the async fn / generator.

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [December 6, 2019, 2:41pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/7 "2019-12-06T14:41:06Z")

</div>

> [@Migi](#):
>
> But from a practical point of view, I'm not so sure, because that would create lots and lots of warnings, nagging people to mark functions as `#[might_block]` even though they were never intended to be used in an `async` context.

I meant the compiler would track this and warn end users, not that they would warn for not tagging the functions might block. Indeed, the idea of making it transitive is that users would not have to tag all their functions.

Your point about `Option::map` is good: its possible this would not work at all with higher order functions. However, its also possible that we might be able to run this lint after instantiation, when the type is known, in which case an intelligent enough "transitive" rule would even catch those. Probably not a requirement for the MVP though.

> [@CryZe](#):
>
> What I've run into recently was that I accidentally had a parking\_lot::MutexGuard across an .await and it caused a deadlock (or actually panic because this was in wasm). An idea that I had would be that blocking guard-like data structures could be annotated with

This is interesting! I thought about tagging just `lock` to catch this case, but if you never lock across a yield point or blocking function, locking itself is not really the problem. You're right that an attribute to warn when certain objects are alive across a yield point would be helpful.

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [December 6, 2019, 6:55pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/8 "2019-12-06T18:55:38Z")

</div>

I like the idea of a transitive `#[might_block]` because it lets us treat OS-level blocking (or whatever we apply it to) as an effect. Current effect-like things in Rust are manually annotated at all levels (`async`, `try`/`Result`, `const`), but effects can also be inferred, even polymorphically, so we wouldn't even need to run the lint post-instantiation if it were implemented this way.

---

<div class="post-metadata">

**Author:** ![Diggsey](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/diggsey/32/6311_2.png) [@Diggsey](https://internals.rust-lang.org/u/Diggsey)\
**Post date:** [December 6, 2019, 7:15pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/9 "2019-12-06T19:15:05Z")

</div>

I really like the "cant\_yield" idea, but I'm not sure how feasible the "might\_block" version is...

How do you know whether you're in an async context? Async functions probably call other functions and those functions might block. Does rustc have to analyse the transitive call graph of every async function? What about when the Future trait is implemented directly?

Also, it's not necessarily an error to block in an async function, it depends on the executor/what else is running.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [December 6, 2019, 7:24pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/10 "2019-12-06T19:24:31Z")

</div>

cc @eddyb and @Zoxc re. the transitive idea; I wonder how much of a hit that would be for compile times.

---

<div class="post-metadata">

**Author:** ![llogiq](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/llogiq/32/13692_2.png) [@llogiq](https://internals.rust-lang.org/u/llogiq)\
**Post date:** [December 7, 2019, 3:57pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/11 "2019-12-07T15:57:13Z")

</div>

I think we shouldn't make it transitive below the crate level. That way, we can have a lint that marks all exported non-`#[might_block]` functions that call into `#[might_block]` functions transitively – we should have the complete call graph of a crate available anyway.

This would reduce the burden of annotating to public functions and keep our analysis crate-local.

---

<div class="post-metadata">

**Author:** ![DavidGHorsman](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/davidghorsman/32/6622_2.png) [@DavidGHorsman](https://internals.rust-lang.org/u/DavidGHorsman)\
**Post date:** [December 8, 2019, 1:17am UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/13 "2019-12-08T01:17:22Z")

</div>

Do I correctly understand that can be easily extended? IE with attributes?

---

<div class="post-metadata">

**Author:** ![DavidGHorsman](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/davidghorsman/32/6622_2.png) [@DavidGHorsman](https://internals.rust-lang.org/u/DavidGHorsman)\
**Post date:** [December 8, 2019, 1:31am UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/14 "2019-12-08T01:31:55Z")

</div>

Well that was a great point. But it implies if I maintain defaults and link crates a lint could read it. In a seperate crate of course.

---

<div class="post-metadata">

**Author:** ![DavidGHorsman](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/davidghorsman/32/6622_2.png) [@DavidGHorsman](https://internals.rust-lang.org/u/DavidGHorsman)\
**Post date:** [December 8, 2019, 1:37am UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/15 "2019-12-08T01:37:58Z")

</div>

Of course. You can't argue the block is not "inherited" generally. Provided that you can override that and otherwise not break anything. IE Still retains your current flexibility.

---

<div class="post-metadata">

**Author:** ![bill\_myers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bill_myers/32/4085_2.png) [@bill\_myers](https://internals.rust-lang.org/u/bill_myers)\
**Post date:** [December 9, 2019, 12:53pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/16 "2019-12-09T12:53:27Z")

</div>

Maybe this should be generalized to a general effect system, i.e. have `#[might(Block)]` instead of `#[might_block]` where Block is an effect.

---

<div class="post-metadata">

**Author:** ![skade](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skade/32/3333_2.png) [@skade](https://internals.rust-lang.org/u/skade)\
**Post date:** [December 10, 2019, 12:55pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/17 "2019-12-10T12:55:45Z")

</div>

I'm not fully convinced, but I think additional tooling around this kind of problem could set Rust apart from other languages. A danger I see is ending up with something that people _might_ take for authoritative, while it can really ever be a best effort. There's a danger of building a feature that people rely on and get frustrated when something blocks that wasn't marked.

So, what's necessary before introducing such a feature: figuring out what a metric for "good enough" is and where we cross the boundary where this feature is useful in most cases.

What I am wondering: is it possible to encode "this future includes a blocking call at location `xyz`" and let an executor use that information at runtime?

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [December 10, 2019, 12:59pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/18 "2019-12-10T12:59:31Z")

</div>

> [@skade](#):
>
> A danger I see is ending up with something that people _might_ take for authoritative, while it can really ever be a best effort. There's a danger of building a feature that people rely on and get frustrated when something blocks that wasn't marked.

I agree. I get very nervous about the expectations users will draw (and also scope creep) when we start talking about "blocking as an effect"

---

<div class="post-metadata">

**Author:** ![skade](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skade/32/3333_2.png) [@skade](https://internals.rust-lang.org/u/skade)\
**Post date:** [December 10, 2019, 2:07pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/19 "2019-12-10T14:07:00Z")

</div>

TBH, _if_ such a feature can be designed well, I'd prefer it much over many syntax additions.

Annotations will always be framed as scope creep, while I see them as a very good capability to encode facts that can't easily be derived by the compiler.

---

<div class="post-metadata">

**Author:** ![kellytk](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kellytk/32/6347_2.png) [@kellytk](https://internals.rust-lang.org/u/kellytk)\
**Post date:** [December 11, 2019, 10:46am UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/20 "2019-12-11T10:46:33Z")

</div>

Could the blocking annotation be used to make lints warning when a function's call graph depth exceeds a certain number of blocking annotated functions? Or is that naive and not actually useful in performance optimization?

Could the blocking annotation be specified with an optional low/high modifier where adding the values of an entire call graph (blocking+modifier calls blocking+modifier calls..) becomes helpful to the developer in optimizing queue assignment?

---

<div class="post-metadata">

**Author:** ![eminence](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/eminence/32/4018_2.png) [@eminence](https://internals.rust-lang.org/u/eminence)\
**Post date:** [December 11, 2019, 2:58pm UTC](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440/21 "2019-12-11T14:58:13Z")

</div>

> [@withoutboats](#):
>
> The attribute could also have an option for specifying a nonblocking alternative, though for std of course there are no nonblocking alternatives available in std.

I think this is an important point, I'm glad you mentioned it. I think developers would become frustrated if they were faced with warnings in their code, but had no clear idea about how to address them.

In addition to possible suggestions built directly into the attribute, could we consider a new chapter in the rust async book that covers this topic? (stjepang's recent [blog post](https://.github.io/2019/12/04/blocking-inside-async-code.html) on this topic is also a great intro)

[Next page](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440.md?page=2)
