aio-libs / aio-libs/aiopg

connect() fails when multiple hosts listed in dsn

未关闭
#647 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
Python
星标
1.4k
派生
170
PR 合并指标
30 天内没有已合并 PR

描述

If you are using streaming replication on your PG servers, and want to list your secondary server in the host list for failover (example below), aiopg will fail raising `psycopg2.OperationalError: asynchronous connection attempt underway` if the _first_ server is _unavailable_. The same thing happens for both a single connection or a pool. This I have written the same test in psycopg2 directly as well as using asyncpg, and it works successfully in both - it only fails in aiopg.

Setup:
Python 3.5.7
aiopg 1.0.0
psycopg2 2.8.4
RH7 Linux running Postgres 12

Environment:
`realserver1` is a RH7 Linux postgres server running on port 5433, with streaming replication enabled to `realserver2`. Note you do not need this to test! I can reproduce this by using a single postgres server, and simply listing a non-running server. Example - `dsn = '... port=5000,5433 host=realserver1,realserver1'`.

```
import asyncio
import aiopg

dsn = 'dbname=testdb user=testdb password=passwd port=5433 host=realserver1,realserver2'

async def go_pool():
print('starting')
async with aiopg.create_pool(dsn, timeout=3, minsize=0) as pool:
print('pool created')
async with pool.acquire() as conn:
print('connection aquired')
async with conn.cursor() as cur:
print('cursor created')
await cur.execute("SELECT 1")
print('selected')
ret = []
async for row in cur:
ret.append(row)
assert ret == [(1,)]
print('completed successfully!')

async def go_conn():
print('starting')
conn = await aiopg.connect(dsn=dsn, timeout=3)
print('connection aquired')
cur = await conn.cursor()
await cur.execute("SELECT 1")
ret = await cur.fetchone()
assert ret == (1,), ret
print('completed successfully!')
cur.close()
conn.close()

go = go_pool
loop = asyncio.get_event_loop()
loop.run_until_complete(go())
```

```$ python test_aiopg.py
starting
pool created
Traceback (most recent call last):
File "test_aiopg.py", line 47, in
loop.run_until_complete(go())
File "/usr/local/lib/python3.5/asyncio/base_events.py", line 467, in run_until_complete
return future.result()
File "/usr/local/lib/python3.5/asyncio/futures.py", line 294, in result
raise self._exception
File "/usr/local/lib/python3.5/asyncio/tasks.py", line 242, in _step
result = coro.throw(exc)
File "test_aiopg.py", line 20, in go
async with pool.acquire() as conn:
File "~/venv/lib/python3.5/site-packages/aiopg/utils.py", line 94, in __aenter__
self._obj = await self._coro
File "~/venv/lib/python3.5/site-packages/aiopg/pool.py", line 164, in _acquire
await self._fill_free_pool(True)
File "~/venv/lib/python3.5/site-packages/aiopg/pool.py", line 217, in _fill_free_pool
**self._conn_kwargs)
File "~/venv/lib/python3.5/site-packages/aiopg/connection.py", line 551, in _connect
await self._poll(self._waiter, self._timeout)
File "~/venv/lib/python3.5/site-packages/aiopg/connection.py", line 209, in _poll
await asyncio.shield(cancel(), loop=self._loop)
File "/usr/local/lib/python3.5/asyncio/futures.py", line 381, in __iter__
yield self # This tells Task to wait for completion.
File "/usr/local/lib/python3.5/asyncio/tasks.py", line 310, in _wakeup
future.result()
File "/usr/local/lib/python3.5/asyncio/futures.py", line 294, in result
raise self._exception
File "/usr/local/lib/python3.5/asyncio/tasks.py", line 240, in _step
result = coro.send(None)
File "~/venv/lib/python3.5/site-packages/aiopg/connection.py", line 195, in cancel
self._conn.cancel()
psycopg2.OperationalError: asynchronous connection attempt underway
```

This should work - it works when directly using psycopg2

```
import psycopg2
from psycopg2.pool import SimpleConnectionPool, ThreadedConnectionPool

#CP = SimpleConnectionPool
CP = ThreadedConnectionPool

dsn = 'dbname=testdb user=testdb password=passwd port=5433 host=realserver1,realserver2'
url = 'postgres://testdb:passwd@realserver1:5433,realserver2:5433/testdb'

pool = CP(1,2,dsn=url)
conn = pool.getconn()
cur = conn.cursor()

cur.execute('select 1')
ret = cur.fetchall()
assert ret == [(1,)]
print('completed successfully!')

cur.close()
pool.closeall()
```

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。