Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MemoryObjectStream can drop items when the receiving end is cancelled #728

Closed
2 tasks done
agronholm opened this issue May 9, 2024 · 7 comments · Fixed by #735
Closed
2 tasks done

MemoryObjectStream can drop items when the receiving end is cancelled #728

agronholm opened this issue May 9, 2024 · 7 comments · Fixed by #735
Labels
bug Something isn't working

Comments

@agronholm
Copy link
Owner

agronholm commented May 9, 2024

Things to check first

  • I have searched the existing issues and didn't find my bug already reported there

  • I have checked that my bug is still present in the latest release

AnyIO version

4.3.0

Python version

3.8

What happened?

If a task (A) sends an item to another task (B) via a memory object stream, and task B is in a state of waiting for an item, and has a pending cancellation, the item is still sent to B but as cancellation is then delivered to B, that item is essentially dropped on the floor.

A similar issue was reported in #146, but it seems that it wasn't fixed as thoroughly as I had hoped.

How can we reproduce the bug?

import anyio
from anyio import (
    CancelScope, create_memory_object_stream, create_task_group,
    wait_all_tasks_blocked
)

async def receiver(receive, task_status):
    with CancelScope() as cancel_scope:
        task_status.started(cancel_scope)
        await receive.receive()

async def main():
    send, receive = create_memory_object_stream(1)
    with send, receive:
        async with create_task_group() as tg:
            cancel_scope = await tg.start(receiver, receive)
            await wait_all_tasks_blocked()
            cancel_scope.cancel()
            send.send_nowait("item")

        assert receive.receive_nowait() == "item"

anyio.run(main)

The above snippet reproduces the problem (WouldBlock is raised) on both asyncio and Trio. On Trio, if create_memory_object_stream() is replaced with trio.open_memory_channel(), the snippet no longer raises an exception.

@agronholm agronholm added the bug Something isn't working label May 9, 2024
@gschaffner
Copy link
Collaborator

did you mean to include that assert in your reproducer? I would expect assert receive.receive_nowait() == "item", if reachable, to raise WouldBlock:

  • receive_nowait() can only receive an item from a buffer or from a waiting sender, but in your reproducer there is neither: the stream is unbuffered and there are no await send() calls, only send_nowait() calls.

  • looking at history, there's a test relevant to this: I think that your reproducer's assertion is asserting the same thing that test_cancel_during_receive_last_receiver did. test_cancel_during_receive_last_receiver was removed in a3af1da because it was deemed incorrect. IIUC it was incorrect because closing an unbuffered memory object stream pair is supposed to be guaranteed to not drop items (there is no buffer, so there are no items to possibly drop). in the ~day between bd9a310 and a3af1da, AnyIO could push items beyond the buffer's limit, meaning that closing an unbuffered stream pair could incorrectly cause items to be dropped. but a3af1da fixed this and removed the incorrect test.

@gschaffner
Copy link
Collaborator

gschaffner commented May 11, 2024

if I remove that assertion from your reproducer, then I believe your reproducer demonstrates at least one bug, but possibly two:

  1. the bug of AnyIO dropping the item in your reproducer.

  2. the (possible) bug of send_nowait() raising WouldBlock when using trio_memory_channel.send_nowait() but not raising WouldBlock when using anyio_memory_stream.send_nowait().

    unlike (1), this does not cause items to be lost.

I think it's worth discussing these two things separately because (1) is the urgent issue (data loss), and it can be fixed first without doing the harder thing of also fixing (2). in more detail:

  1. this was a regression that was introduced in Added an alternate fix for MemoryObjectReceiveStream.receive()` on asyncio #595. Added an alternate fix for MemoryObjectReceiveStream.receive()` on asyncio #595 as whole should not be totally reverted, as it fixed On asyncio, Event.set() sometimes fails to notify all waiting tasks #536. but partially reverting it would fix (1) and prevent item loss: here's a PR for that: Fix memory streams incorrectly raising cancelled when *_nowait() is called immediately after cancelling send()/receive() #729

  2. it's not clear to me at the moment if this is a bug or not. regarding the send_nowait() and await receive() calls, I'd expect one of two things to happen. either of these options would be fine in the sense that neither of them can cause AnyIO to drop items:

    1. send_nowait() returns success and await receive.receive() receives the item.

      this is what AnyIO did prior to Added an alternate fix for MemoryObjectReceiveStream.receive()` on asyncio #595, when (1) regressed.

      currently this is almost what AnyIO is doing, except that currently send_nowait() can go through while await receive.receive() raises cancelled, losing an item (i.e. (1)).

      this behavior can be explained as: while the await receive() call's scope gets a cancellation request before send_nowait(), there's no checkpoint between cancel_scope.cancel() and send_nowait(), so the send_nowait() call will happen and will succeed before await receive() has a chance to react to the request for cancellation. at that point, receive() has already received an item, so it's too late for it to raise cancelled (see also Pass along the received item to the next receiver if the task was cancelled #147 (comment)).

    2. send_nowait() raises WouldBlock and await receive.receive() raises cancelled.

      this is the behavior when replacing the AnyIO memory stream with a Trio memory channel. I don't know what Trio's design reason for this is (assuming this was explicitly intentional), but the technical reason is that Trio memory channels are not implemented using Event; they're implemented using wait_task_rescheduled. specifically, Object stream randomly drops items #146 (comment).

    question: is this behavior of Trio intentional/documented? i.e., does Trio document that (ii) will happen and (i) will not? or does Trio leave it undocumented, and it is just an implementation detail whether open_memory_channel is using Event or wait_task_rescheduled under the hood?

    in the case that this is a deemed to be a bug (i.e. if Trio does document this behavior and so AnyIO should have identical behavior to Trio's documented behavior), then i agree with your gitter message that

    I think this could be solved if the sender could skip recipients that have been cancelled

    doing that in a backend agnostic manner is the tough part though :)

    I think that one backend-agnostic manner to do this could be to implement anyio.lowlevel.wait_task_rescheduled and have memory streams use that instead of Event.

    also, in the case that this is deemed to be a bug, here's a test: e70b0e4

(1) is the urgent problem (dropped items). since it's straightforward to fix, I think that it should be fixed first, and whether (2) is a bug or not (and, if so, how to resolve it in a backend-agnostic manner) can be figured out later (perhaps in a separate issue).

@agronholm
Copy link
Owner Author

Ah, my intention was to create a memory object stream with a buffer. Then the assert makes sense, yes?

@agronholm
Copy link
Owner Author

I've adjusted the snippet accordingly.

@agronholm
Copy link
Owner Author

Compare to the use of open_memory_channel():

import anyio
from anyio import (
    CancelScope, create_task_group,
    wait_all_tasks_blocked,
)
from trio import open_memory_channel

async def receiver(receive, task_status):
    with CancelScope() as cancel_scope:
        task_status.started(cancel_scope)
        await receive.receive()

async def main():
    send, receive = open_memory_channel(1)
    with send, receive:
        async with create_task_group() as tg:
            cancel_scope = await tg.start(receiver, receive)
            await wait_all_tasks_blocked()
            cancel_scope.cancel()
            send.send_nowait("item")

        assert receive.receive_nowait() == "item"

anyio.run(main, backend="trio")

@gschaffner
Copy link
Collaborator

Ah, my intention was to create a memory object stream with a buffer. Then the assert makes sense, yes?

yes, agreed, assuming that your intention is to test for (2). but only (1) is needed to ensure that the stream isn't dropping items. (2) is a stricter criterion.

it's not clear to me whether (2) is actually a bug or problematic. what did you think about

question: is this behavior of Trio intentional/documented? i.e., does Trio document that (ii) will happen and (i) will not? or does Trio leave it undocumented, and it is just an implementation detail whether open_memory_channel is using Event or wait_task_rescheduled under the hood?

@gschaffner
Copy link
Collaborator

gschaffner commented May 12, 2024

i have just written some more tests that are also closely related, plus a closely related fix. (these tests are currently in branch #729 (2b09585).) here is a summary of all of these variations of #146 that that branch is currently testing for (I think that this list makes a good summary of the relationships between these issues):

  • misbehavior when MemoryObjectReceiveStream.receive() is cancelled. the misbehavior is in the form of dropped items, i.e. neither the attempted sender nor the attempted receiver think they are responsible for the item.

    this is #146. it has two cases:

    • test_cancel_during_receive_after_send_nowait: this has been passing since 2020 (although it no longer supports native cancellations since #595, as mentioned in #595 (comment)).

    • test_cancel_during_receive_before_send_nowait: this is #728 (sense (1)). it had been passing since 2020 but started failing in #595.

  • misbehavior when MemoryObjectSendStream.send() is cancelled. the misbehavior is in the form of simultaneously-sent-and-not-sent items, i.e. both the attempted sender and the attempted receiver think they are responsible for the item.

    this issue was mentioned in #536:

    MemoryObjectSendStream.send(item) can raise cancelled after item has been delivered to a receiver! this MemoryObjectSendStream.send issue is just the send_event.wait() case to #146's receive_event.wait() case, i believe

    this also has two cases. they are analogous to #146's cases:

    • test_cancel_during_send_after_receive_nowait: this has been passing since #595.

    • test_cancel_during_send_before_receive_nowait: this is analogous to #728 (sense (1)). it is failing on master.

  • misbehavior when Event.wait() is cancelled: there are also two cases here:

    • test_event_wait_before_set_before_cancel: this was #536; it was fixed by #595 (although it remains broken with native cancellations).

    • test_event_wait_before_cancel_before_set: this has been behaving correctly for a while.

      this is closely related to #728 (sense (2)), because this Event behavior is the reason why the regression #728 (sense (2)) happened. specifically, this Event behavior is why it's not possible to implement Trio's memory channel cancellation semantics (the behavior of its abort_fns) by using purely the cancellation semantics of Event.

agronholm added a commit that referenced this issue May 14, 2024
Check if the receiving task has a pending cancellation before sending an item.

Fixes #728.
agronholm added a commit that referenced this issue May 26, 2024
Check if the receiving task has a pending cancellation before sending an item.

Fixes #728.
mkjpryor pushed a commit to azimuth-cloud/cluster-api-addon-provider that referenced this issue May 28, 2024
Bumps [anyio](https://github.com/agronholm/anyio) from 4.3.0 to 4.4.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/agronholm/anyio/releases">anyio's
releases</a>.</em></p>
<blockquote>
<h2>4.4.0</h2>
<ul>
<li>Added the <code>BlockingPortalProvider</code> class to aid with
constructing synchronous counterparts to asynchronous interfaces that
would otherwise require multiple blocking portals</li>
<li>Added <code>__slots__</code> to <code>AsyncResource</code> so that
child classes can use <code>__slots__</code> (<a
href="https://redirect.github.com/agronholm/anyio/pull/733">#733</a>; PR
by Justin Su)</li>
<li>Added the <code>TaskInfo.has_pending_cancellation()</code>
method</li>
<li>Fixed erroneous <code>RuntimeError: called 'started' twice on the
same task status</code> when cancelling a task in a TaskGroup created
with the <code>start()</code> method before the first checkpoint is
reached after calling <code>task_status.started()</code> (<a
href="https://redirect.github.com/agronholm/anyio/issues/706">#706</a>;
PR by Dominik Schwabe)</li>
<li>Fixed two bugs with <code>TaskGroup.start()</code> on asyncio:
<ul>
<li>Fixed erroneous <code>RuntimeError: called 'started' twice on the
same task status</code> when cancelling a task in a TaskGroup created
with the <code>start()</code> method before the first checkpoint is
reached after calling <code>task_status.started()</code> (<a
href="https://redirect.github.com/agronholm/anyio/issues/706">#706</a>;
PR by Dominik Schwabe)</li>
<li>Fixed the entire task group being cancelled if a
<code>TaskGroup.start()</code> call gets cancelled (<a
href="https://redirect.github.com/agronholm/anyio/issues/685">#685</a>,
<a
href="https://redirect.github.com/agronholm/anyio/issues/710">#710</a>)</li>
</ul>
</li>
<li>Fixed a race condition that caused crashes when multiple event loops
of the same backend were running in separate threads and simultaneously
attempted to use AnyIO for their first time (<a
href="https://redirect.github.com/agronholm/anyio/issues/425">#425</a>;
PR by David Jiricek and Ganden Schaffner)</li>
<li>Fixed cancellation delivery on asyncio incrementing the wrong cancel
scope's cancellation counter when cascading a cancel operation to a
child scope, thus failing to uncancel the host task (<a
href="https://redirect.github.com/agronholm/anyio/issues/716">#716</a>)</li>
<li>Fixed erroneous <code>TypedAttributeLookupError</code> if a typed
attribute getter raises <code>KeyError</code></li>
<li>Fixed the asyncio backend not respecting the
<code>PYTHONASYNCIODEBUG</code> environment variable when setting the
<code>debug</code> flag in <code>anyio.run()</code></li>
<li>Fixed <code>SocketStream.receive()</code> not detecting EOF on
asyncio if there is also data in the read buffer (<a
href="https://redirect.github.com/agronholm/anyio/issues/701">#701</a>)</li>
<li>Fixed <code>MemoryObjectStream</code> dropping an item if the item
is delivered to a recipient that is waiting to receive an item but has a
cancellation pending (<a
href="https://redirect.github.com/agronholm/anyio/issues/728">#728</a>)</li>
<li>Emit a <code>ResourceWarning</code> for
<code>MemoryObjectReceiveStream</code> and
<code>MemoryObjectSendStream</code> that were garbage collected without
being closed (PR by Andrey Kazantcev)</li>
<li>Fixed <code>MemoryObjectSendStream.send()</code> not raising
<code>BrokenResourceError</code> when the last corresponding
<code>MemoryObjectReceiveStream</code> is closed while waiting to send a
falsey item (<a
href="https://redirect.github.com/agronholm/anyio/issues/731">#731</a>;
PR by Ganden Schaffner)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/agronholm/anyio/blob/master/docs/versionhistory.rst">anyio's
changelog</a>.</em></p>
<blockquote>
<h1>Version history</h1>
<p>This library adheres to <code>Semantic Versioning 2.0
&lt;http://semver.org/&gt;</code>_.</p>
<p><strong>4.4.0</strong></p>
<ul>
<li>
<p>Added the <code>BlockingPortalProvider</code> class to aid with
constructing synchronous
counterparts to asynchronous interfaces that would otherwise require
multiple blocking
portals</p>
</li>
<li>
<p>Added <code>__slots__</code> to <code>AsyncResource</code> so that
child classes can use <code>__slots__</code>
(<code>[#733](agronholm/anyio#733)
&lt;https://github.com/agronholm/anyio/pull/733&gt;</code>_; PR by
Justin Su)</p>
</li>
<li>
<p>Added the <code>TaskInfo.has_pending_cancellation()</code> method</p>
</li>
<li>
<p>Fixed erroneous <code>RuntimeError: called 'started' twice on the
same task status</code>
when cancelling a task in a TaskGroup created with the
<code>start()</code> method before
the first checkpoint is reached after calling
<code>task_status.started()</code>
(<code>[#706](agronholm/anyio#706)
&lt;https://github.com/agronholm/anyio/issues/706&gt;</code>_; PR by
Dominik Schwabe)</p>
</li>
<li>
<p>Fixed two bugs with <code>TaskGroup.start()</code> on asyncio:</p>
<ul>
<li>Fixed erroneous <code>RuntimeError: called 'started' twice on the
same task status</code>
when cancelling a task in a TaskGroup created with the
<code>start()</code> method before
the first checkpoint is reached after calling
<code>task_status.started()</code>
(<code>[#706](agronholm/anyio#706)
&lt;https://github.com/agronholm/anyio/issues/706&gt;</code>_; PR by
Dominik Schwabe)</li>
<li>Fixed the entire task group being cancelled if a
<code>TaskGroup.start()</code> call gets
cancelled (<code>[#685](agronholm/anyio#685)
&lt;https://github.com/agronholm/anyio/issues/685&gt;</code><em>,
<code>[#710](agronholm/anyio#710)
&lt;https://github.com/agronholm/anyio/issues/710&gt;</code></em>)</li>
</ul>
</li>
<li>
<p>Fixed a race condition that caused crashes when multiple event loops
of the same
backend were running in separate threads and simultaneously attempted to
use AnyIO for
their first time
(<code>[#425](agronholm/anyio#425)
&lt;https://github.com/agronholm/anyio/issues/425&gt;</code>_; PR by
David
Jiricek and Ganden Schaffner)</p>
</li>
<li>
<p>Fixed cancellation delivery on asyncio incrementing the wrong cancel
scope's
cancellation counter when cascading a cancel operation to a child scope,
thus failing
to uncancel the host task
(<code>[#716](agronholm/anyio#716)
&lt;https://github.com/agronholm/anyio/issues/716&gt;</code>_)</p>
</li>
<li>
<p>Fixed erroneous <code>TypedAttributeLookupError</code> if a typed
attribute getter raises
<code>KeyError</code></p>
</li>
<li>
<p>Fixed the asyncio backend not respecting the
<code>PYTHONASYNCIODEBUG</code> environment
variable when setting the <code>debug</code> flag in
<code>anyio.run()</code></p>
</li>
<li>
<p>Fixed <code>SocketStream.receive()</code> not detecting EOF on
asyncio if there is also data in
the read buffer
(<code>[#701](agronholm/anyio#701)
&lt;https://github.com/agronholm/anyio/issues/701&gt;</code>_)</p>
</li>
<li>
<p>Fixed <code>MemoryObjectStream</code> dropping an item if the item is
delivered to a recipient
that is waiting to receive an item but has a cancellation pending
(<code>[#728](agronholm/anyio#728)
&lt;https://github.com/agronholm/anyio/issues/728&gt;</code>_)</p>
</li>
<li>
<p>Emit a <code>ResourceWarning</code> for
<code>MemoryObjectReceiveStream</code> and
<code>MemoryObjectSendStream</code> that were garbage collected without
being closed (PR by
Andrey Kazantcev)</p>
</li>
<li>
<p>Fixed <code>MemoryObjectSendStream.send()</code> not raising
<code>BrokenResourceError</code> when the
last corresponding <code>MemoryObjectReceiveStream</code> is closed
while waiting to send a
falsey item (<code>[#731](agronholm/anyio#731)
&lt;https://github.com/agronholm/anyio/issues/731&gt;</code>_; PR by
Ganden
Schaffner)</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/agronholm/anyio/commit/053e8f0a0f7b0f4a47a012eb5c6b1d9d84344e6a"><code>053e8f0</code></a>
Bumped up the version</li>
<li><a
href="https://github.com/agronholm/anyio/commit/e7f750b96f5416d8ae932e15d726b5d03de80b67"><code>e7f750b</code></a>
Fixed memory object stream sometimes dropping sent items (<a
href="https://redirect.github.com/agronholm/anyio/issues/735">#735</a>)</li>
<li><a
href="https://github.com/agronholm/anyio/commit/9f5f14b3eb57f6965fc2c16879df93263bb020ea"><code>9f5f14b</code></a>
Fixed task group getting cancelled if start() gets cancelled (<a
href="https://redirect.github.com/agronholm/anyio/issues/717">#717</a>)</li>
<li><a
href="https://github.com/agronholm/anyio/commit/8b648bc213a85613b9441913b82a14d9cd839048"><code>8b648bc</code></a>
Adjusted the pull request template</li>
<li><a
href="https://github.com/agronholm/anyio/commit/3ff5e9a6f1813152a7cc9ff27a8394a51812a040"><code>3ff5e9a</code></a>
Rearranged changelog items</li>
<li><a
href="https://github.com/agronholm/anyio/commit/541d1f8197dfa36076f93b39e73ee5ad06012469"><code>541d1f8</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/agronholm/anyio/issues/734">#734</a>)</li>
<li><a
href="https://github.com/agronholm/anyio/commit/8a076900333b6b333f1748dd8d1e8ae8079a2924"><code>8a07690</code></a>
Fix <code>MemoryObjectSendStream.send(falsey)</code> not raising
<code>BrokenResourceError</code> w...</li>
<li><a
href="https://github.com/agronholm/anyio/commit/4b3de9737672df67b691f38543427e4869639f45"><code>4b3de97</code></a>
Adjust the headings in the PR template</li>
<li><a
href="https://github.com/agronholm/anyio/commit/dfc44cf3c8c5444713258d0f1fda03e425240054"><code>dfc44cf</code></a>
Added <code>__slots__</code> to <code>AsyncResource</code> (<a
href="https://redirect.github.com/agronholm/anyio/issues/733">#733</a>)</li>
<li><a
href="https://github.com/agronholm/anyio/commit/96920b054c4d0c76ad440f36d7173ab5d5c86948"><code>96920b0</code></a>
Fix typo in PR template (<a
href="https://redirect.github.com/agronholm/anyio/issues/730">#730</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/agronholm/anyio/compare/4.3.0...4.4.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=anyio&package-manager=pip&previous-version=4.3.0&new-version=4.4.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
mkjpryor pushed a commit to azimuth-cloud/azimuth that referenced this issue May 28, 2024
Bumps [anyio](https://github.com/agronholm/anyio) from 4.3.0 to 4.4.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/agronholm/anyio/releases">anyio's
releases</a>.</em></p>
<blockquote>
<h2>4.4.0</h2>
<ul>
<li>Added the <code>BlockingPortalProvider</code> class to aid with
constructing synchronous counterparts to asynchronous interfaces that
would otherwise require multiple blocking portals</li>
<li>Added <code>__slots__</code> to <code>AsyncResource</code> so that
child classes can use <code>__slots__</code> (<a
href="https://redirect.github.com/agronholm/anyio/pull/733">#733</a>; PR
by Justin Su)</li>
<li>Added the <code>TaskInfo.has_pending_cancellation()</code>
method</li>
<li>Fixed erroneous <code>RuntimeError: called 'started' twice on the
same task status</code> when cancelling a task in a TaskGroup created
with the <code>start()</code> method before the first checkpoint is
reached after calling <code>task_status.started()</code> (<a
href="https://redirect.github.com/agronholm/anyio/issues/706">#706</a>;
PR by Dominik Schwabe)</li>
<li>Fixed two bugs with <code>TaskGroup.start()</code> on asyncio:
<ul>
<li>Fixed erroneous <code>RuntimeError: called 'started' twice on the
same task status</code> when cancelling a task in a TaskGroup created
with the <code>start()</code> method before the first checkpoint is
reached after calling <code>task_status.started()</code> (<a
href="https://redirect.github.com/agronholm/anyio/issues/706">#706</a>;
PR by Dominik Schwabe)</li>
<li>Fixed the entire task group being cancelled if a
<code>TaskGroup.start()</code> call gets cancelled (<a
href="https://redirect.github.com/agronholm/anyio/issues/685">#685</a>,
<a
href="https://redirect.github.com/agronholm/anyio/issues/710">#710</a>)</li>
</ul>
</li>
<li>Fixed a race condition that caused crashes when multiple event loops
of the same backend were running in separate threads and simultaneously
attempted to use AnyIO for their first time (<a
href="https://redirect.github.com/agronholm/anyio/issues/425">#425</a>;
PR by David Jiricek and Ganden Schaffner)</li>
<li>Fixed cancellation delivery on asyncio incrementing the wrong cancel
scope's cancellation counter when cascading a cancel operation to a
child scope, thus failing to uncancel the host task (<a
href="https://redirect.github.com/agronholm/anyio/issues/716">#716</a>)</li>
<li>Fixed erroneous <code>TypedAttributeLookupError</code> if a typed
attribute getter raises <code>KeyError</code></li>
<li>Fixed the asyncio backend not respecting the
<code>PYTHONASYNCIODEBUG</code> environment variable when setting the
<code>debug</code> flag in <code>anyio.run()</code></li>
<li>Fixed <code>SocketStream.receive()</code> not detecting EOF on
asyncio if there is also data in the read buffer (<a
href="https://redirect.github.com/agronholm/anyio/issues/701">#701</a>)</li>
<li>Fixed <code>MemoryObjectStream</code> dropping an item if the item
is delivered to a recipient that is waiting to receive an item but has a
cancellation pending (<a
href="https://redirect.github.com/agronholm/anyio/issues/728">#728</a>)</li>
<li>Emit a <code>ResourceWarning</code> for
<code>MemoryObjectReceiveStream</code> and
<code>MemoryObjectSendStream</code> that were garbage collected without
being closed (PR by Andrey Kazantcev)</li>
<li>Fixed <code>MemoryObjectSendStream.send()</code> not raising
<code>BrokenResourceError</code> when the last corresponding
<code>MemoryObjectReceiveStream</code> is closed while waiting to send a
falsey item (<a
href="https://redirect.github.com/agronholm/anyio/issues/731">#731</a>;
PR by Ganden Schaffner)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/agronholm/anyio/blob/master/docs/versionhistory.rst">anyio's
changelog</a>.</em></p>
<blockquote>
<h1>Version history</h1>
<p>This library adheres to <code>Semantic Versioning 2.0
&lt;http://semver.org/&gt;</code>_.</p>
<p><strong>4.4.0</strong></p>
<ul>
<li>
<p>Added the <code>BlockingPortalProvider</code> class to aid with
constructing synchronous
counterparts to asynchronous interfaces that would otherwise require
multiple blocking
portals</p>
</li>
<li>
<p>Added <code>__slots__</code> to <code>AsyncResource</code> so that
child classes can use <code>__slots__</code>
(<code>[#733](agronholm/anyio#733)
&lt;https://github.com/agronholm/anyio/pull/733&gt;</code>_; PR by
Justin Su)</p>
</li>
<li>
<p>Added the <code>TaskInfo.has_pending_cancellation()</code> method</p>
</li>
<li>
<p>Fixed erroneous <code>RuntimeError: called 'started' twice on the
same task status</code>
when cancelling a task in a TaskGroup created with the
<code>start()</code> method before
the first checkpoint is reached after calling
<code>task_status.started()</code>
(<code>[#706](agronholm/anyio#706)
&lt;https://github.com/agronholm/anyio/issues/706&gt;</code>_; PR by
Dominik Schwabe)</p>
</li>
<li>
<p>Fixed two bugs with <code>TaskGroup.start()</code> on asyncio:</p>
<ul>
<li>Fixed erroneous <code>RuntimeError: called 'started' twice on the
same task status</code>
when cancelling a task in a TaskGroup created with the
<code>start()</code> method before
the first checkpoint is reached after calling
<code>task_status.started()</code>
(<code>[#706](agronholm/anyio#706)
&lt;https://github.com/agronholm/anyio/issues/706&gt;</code>_; PR by
Dominik Schwabe)</li>
<li>Fixed the entire task group being cancelled if a
<code>TaskGroup.start()</code> call gets
cancelled (<code>[#685](agronholm/anyio#685)
&lt;https://github.com/agronholm/anyio/issues/685&gt;</code><em>,
<code>[#710](agronholm/anyio#710)
&lt;https://github.com/agronholm/anyio/issues/710&gt;</code></em>)</li>
</ul>
</li>
<li>
<p>Fixed a race condition that caused crashes when multiple event loops
of the same
backend were running in separate threads and simultaneously attempted to
use AnyIO for
their first time
(<code>[#425](agronholm/anyio#425)
&lt;https://github.com/agronholm/anyio/issues/425&gt;</code>_; PR by
David
Jiricek and Ganden Schaffner)</p>
</li>
<li>
<p>Fixed cancellation delivery on asyncio incrementing the wrong cancel
scope's
cancellation counter when cascading a cancel operation to a child scope,
thus failing
to uncancel the host task
(<code>[#716](agronholm/anyio#716)
&lt;https://github.com/agronholm/anyio/issues/716&gt;</code>_)</p>
</li>
<li>
<p>Fixed erroneous <code>TypedAttributeLookupError</code> if a typed
attribute getter raises
<code>KeyError</code></p>
</li>
<li>
<p>Fixed the asyncio backend not respecting the
<code>PYTHONASYNCIODEBUG</code> environment
variable when setting the <code>debug</code> flag in
<code>anyio.run()</code></p>
</li>
<li>
<p>Fixed <code>SocketStream.receive()</code> not detecting EOF on
asyncio if there is also data in
the read buffer
(<code>[#701](agronholm/anyio#701)
&lt;https://github.com/agronholm/anyio/issues/701&gt;</code>_)</p>
</li>
<li>
<p>Fixed <code>MemoryObjectStream</code> dropping an item if the item is
delivered to a recipient
that is waiting to receive an item but has a cancellation pending
(<code>[#728](agronholm/anyio#728)
&lt;https://github.com/agronholm/anyio/issues/728&gt;</code>_)</p>
</li>
<li>
<p>Emit a <code>ResourceWarning</code> for
<code>MemoryObjectReceiveStream</code> and
<code>MemoryObjectSendStream</code> that were garbage collected without
being closed (PR by
Andrey Kazantcev)</p>
</li>
<li>
<p>Fixed <code>MemoryObjectSendStream.send()</code> not raising
<code>BrokenResourceError</code> when the
last corresponding <code>MemoryObjectReceiveStream</code> is closed
while waiting to send a
falsey item (<code>[#731](agronholm/anyio#731)
&lt;https://github.com/agronholm/anyio/issues/731&gt;</code>_; PR by
Ganden
Schaffner)</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/agronholm/anyio/commit/053e8f0a0f7b0f4a47a012eb5c6b1d9d84344e6a"><code>053e8f0</code></a>
Bumped up the version</li>
<li><a
href="https://github.com/agronholm/anyio/commit/e7f750b96f5416d8ae932e15d726b5d03de80b67"><code>e7f750b</code></a>
Fixed memory object stream sometimes dropping sent items (<a
href="https://redirect.github.com/agronholm/anyio/issues/735">#735</a>)</li>
<li><a
href="https://github.com/agronholm/anyio/commit/9f5f14b3eb57f6965fc2c16879df93263bb020ea"><code>9f5f14b</code></a>
Fixed task group getting cancelled if start() gets cancelled (<a
href="https://redirect.github.com/agronholm/anyio/issues/717">#717</a>)</li>
<li><a
href="https://github.com/agronholm/anyio/commit/8b648bc213a85613b9441913b82a14d9cd839048"><code>8b648bc</code></a>
Adjusted the pull request template</li>
<li><a
href="https://github.com/agronholm/anyio/commit/3ff5e9a6f1813152a7cc9ff27a8394a51812a040"><code>3ff5e9a</code></a>
Rearranged changelog items</li>
<li><a
href="https://github.com/agronholm/anyio/commit/541d1f8197dfa36076f93b39e73ee5ad06012469"><code>541d1f8</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/agronholm/anyio/issues/734">#734</a>)</li>
<li><a
href="https://github.com/agronholm/anyio/commit/8a076900333b6b333f1748dd8d1e8ae8079a2924"><code>8a07690</code></a>
Fix <code>MemoryObjectSendStream.send(falsey)</code> not raising
<code>BrokenResourceError</code> w...</li>
<li><a
href="https://github.com/agronholm/anyio/commit/4b3de9737672df67b691f38543427e4869639f45"><code>4b3de97</code></a>
Adjust the headings in the PR template</li>
<li><a
href="https://github.com/agronholm/anyio/commit/dfc44cf3c8c5444713258d0f1fda03e425240054"><code>dfc44cf</code></a>
Added <code>__slots__</code> to <code>AsyncResource</code> (<a
href="https://redirect.github.com/agronholm/anyio/issues/733">#733</a>)</li>
<li><a
href="https://github.com/agronholm/anyio/commit/96920b054c4d0c76ad440f36d7173ab5d5c86948"><code>96920b0</code></a>
Fix typo in PR template (<a
href="https://redirect.github.com/agronholm/anyio/issues/730">#730</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/agronholm/anyio/compare/4.3.0...4.4.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=anyio&package-manager=pip&previous-version=4.3.0&new-version=4.4.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants