MagicStack / MagicStack/asyncpg

Terminate function does not work when a stream is cancelled prematurely when in an anyio task group

Open
#1,156 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
8.1k
Forks
468
PR merge metrics
No merged PRs in 30d

Description

* **asyncpg version**: 0.29.0
* **PostgreSQL version**: 14.10
* **Do you use a PostgreSQL SaaS? If so, which? Can you reproduce
the issue with a local PostgreSQL install?**: Yes, I can reproduce it locally
* **Python version**: 3.12
* **Platform**: linux and Mac OS
* **Do you use pgbouncer?**: No
* **Did you install asyncpg with pip?**: Yes
* **If you built asyncpg locally, which version of Cython did you use?**: n/a
* **Can the issue be reproduced under both asyncio and
[uvloop](https://github.com/magicstack/uvloop)?**: No, the issue is not producible with asyncio only with anyio

Hi, I have a Fast API application that uses `SQLAlchemy` and `asyncpg`. I opened up a discussion on the SQLAlchemy page [here (full discussion)](https://github.com/sqlalchemy/sqlalchemy/discussions/11128#discussion-6343846) reporting a major problem that affected my application after an update they released.

To summarize the problem and what we concluded in that discussion,

I asynchronously stream data from my API to a client using the `starlette` `StreamingResponse` class which takes advantage of`anyio` under the hood. For some reason when the `anyio` `task group` gets cancelled before the stream is finished the `asyncpg` `terminate` function does not terminate the connection when the `close` function is used first, leaving it stuck in an `idle in transaction` state. This causes connections to run up eventually stopping other applications from creating new connections.

With some help from the SQLAlchemy folks, after some time working through the problem we were able to reproduce a small example of my problem using only the `asyncpg` and `anyio` libraries [here (Example of problem)](https://github.com/sqlalchemy/sqlalchemy/discussions/11128#discussioncomment-9539469)

Any help resolving this issue would be greatly appreciated! If you need any more info from me please do not hesitate to message back

Thanks in advance!

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The minimal reproduction is linked in the SQLAlchemy discussion; start by running it with the reported asyncpg and anyio setup and trace the close-then-terminate path during task-group cancellation. Use asyncpg's terminate and close entry points to locate the connection lifecycle handling. Done means a cancelled stream no longer leaves the connection in an idle in transaction state.

Written by the indexing model from the issue text.

Assessment

Tech stack
fastapi, postgresql, python
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.