Description
- asyncpg version: 0.18.3
- PostgreSQL version: 9.4
- Do you use a PostgreSQL SaaS? If so, which? Can you reproduce
the issue with a local PostgreSQL install?: I use the official Docker image with custom schema and test data. - Python version: 3.7
- Platform: MacOS
- Do you use pgbouncer?: No
- Did you install asyncpg with pip?: Yes
- If you built asyncpg locally, which version of Cython did you use?: -
- Can the issue be reproduced under both asyncio and
uvloop?: Yes
Hello,
I am facing a peculiar problem with the way prepared statements are handled. I use the following architecture:
aiohttp application, which initializes a pool of 1 to 20 db connections on init.
Data is periodically refreshed from the DB (once in a few minutes for most tables). I have a special class which handles the loading of data from DB and caches them to memory and to Redis (since multiple containers of the same app are running and I would like to minimize fetches from DB). This class is instantiated by a factory method which creates (besides other arguments) a load
coroutine, which gets query passed into it by the factory.
The queries have no parameters and are static through out the runtime.
load
functions works by getting a connection from the pool, and calling connection.fetch
on the given query. As per my understanding, the query should then be turned into a prepared statement, cached into a builtin LRU cache, and reused in later calls. However, it seems that each call to load
(which is periodic) gets a new LRU cache for some reason, creating the prepared statements anew. But when I run connection.fetch
on SELECT * FROM pg_prepared_statements
I see that the number of prepared statements held by the connection increases in each call of fetch
.
Indeed, adding some prints to connection.py
I found out that the statements get recreated and put into the cache on each call, since the cache is empty. I thought that perhaps it is because the connections I get from the pool differ, but since pg_prepared_statements
is local to a session (a connection?) I think this is not the case. Indeed, limiting the size of the pool to max_size=1
did not solve this issue.
This causes my Postgres to slowly drain more and more memory until the connections are reset. Disabling the LRU cache with statement_cache_size=0
avoids this, but I believe that this behaviour is not intended.
I tried to make a minimal reproducer but haven't yet succeeded.