asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress

Created on 26 Dec 2016  路  17Comments  路  Source: MagicStack/asyncpg

Hi, here is my code ,please help resovle the problem.thanks a lot.

from sanic import Sanic
from sanic.response import json
import asyncpg
import asyncio
import uvloop
loop = uvloop.new_event_loop()
app = Sanic()
app.debug = True

async def initdb_pool():
    dbdict = {"database":"mqtt","user":"mqtt","password":"mqtt123",
            "host":"192.168.25.100","port":5433}
    return await asyncpg.create_pool(**dbdict)

@app.route("/iot/v1.0/app/auth/<user:[A-z0-9]\w+>/<pwd:[A-z0-9]\w+>/")
async def applogin(request,user,pwd):
    async with engine.acquire() as connection:
        #async with connection.transaction():
        stmt   = await connection.prepare('select key from user_manager_appuser where uname = $1 or email = $2 or phone = $3')
        result =  await stmt.fetchval(user,user,user)
        #    result = await connection.fetchval('select key from user_manager_appuser where uname = $1 or email = $2 or phone = $3',
        #                                        user,user,user)
        if not result:
            return json({'ok':False,'err':'Pwd error'})
        print("result is ",result)
        return json({'ok':True,'data':str(result)})

if __name__ == "__main__":
    engine = loop.run_until_complete(initdb_pool())
    app.run(host="0.0.0.0",port=8000,debug=True)


 curl "http://127.0.0.1:8000/iot/v1.0/app/auth/abc/123456/"
Error: cannot perform operation: another operation is in progress
Exception: Traceback (most recent call last):
  File "/media/yjdwbj/E/py360dev/lib/python3.6/site-packages/sanic/sanic.py", line 194, in handle_request
    response = await response
  File "/opt/python360/lib/python3.6/asyncio/coroutines.py", line 128, in throw
    return self.gen.throw(type, value, traceback)
  File "main.py", line 32, in applogin
    return json({'ok':True,'data':str(result)})
  File "/opt/python360/lib/python3.6/asyncio/coroutines.py", line 109, in __next__
    return self.gen.send(None)
  File "/media/yjdwbj/E/py360dev/lib/python3.6/site-packages/asyncpg/pool.py", line 252, in __aexit__
    await self.pool.release(con)
  File "/opt/python360/lib/python3.6/asyncio/coroutines.py", line 109, in __next__
    return self.gen.send(None)
  File "/media/yjdwbj/E/py360dev/lib/python3.6/site-packages/asyncpg/pool.py", line 184, in release
    await connection.reset()
  File "/opt/python360/lib/python3.6/asyncio/coroutines.py", line 109, in __next__
    return self.gen.send(None)
  File "/media/yjdwbj/E/py360dev/lib/python3.6/site-packages/asyncpg/connection.py", line 411, in reset
    ''')
  File "/opt/python360/lib/python3.6/asyncio/coroutines.py", line 109, in __next__
    return self.gen.send(None)
  File "/media/yjdwbj/E/py360dev/lib/python3.6/site-packages/asyncpg/connection.py", line 170, in execute
    return await self._protocol.query(query, timeout)
  File "asyncpg/protocol/protocol.pyx", line 247, in query (asyncpg/protocol/protocol.c:51830)
  File "asyncpg/protocol/protocol.pyx", line 352, in asyncpg.protocol.protocol.BaseProtocol._ensure_clear_state (asyncpg/protocol/protocol.c:54136)
asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress
need more info

Most helpful comment

@Behzad-S seems like you are using a shared connection and are attempting to run queries concurrently on it. Use asyncpg.Pool and acquire/release a connection for each request.

All 17 comments

I'm not sure your snippet is complete. Where does engine come from? Are you using asyncpgsa, if so, do you get the same result by using asyncpg directly?

Thanks.

Hi, this code is simple clearly, and it was connected database, just use asyncpg to create_pool .

if __name__ == "__main__":
    engine = loop.run_until_complete(initdb_pool())
    app.run(host="0.0.0.0",port=8000,debug=True)

@yjdwbj, you'll have to pass the loop into sanic manually.

if __name__ == "__main__":
    engine = loop.run_until_complete(initdb_pool())
    app.run(host="0.0.0.0",port=8000, debug=True, loop=loop)

@yjdwbj why closed锛烮 met the same problem

@cctse Because the authors not care this bugs.I found openresty instead of it.

@elprans please reopen this issue, full code as follows

from sanic import Sanic
from sanic.response import text
import asyncio
import uvloop
import asyncpg


asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
loop = asyncio.get_event_loop()


app = Sanic(__name__)

async def init_pgpool():
    return await asyncpg.create_pool('postgres://postgres:ssdd@localhost:5433/postgres')

pgpool = loop.run_until_complete(init_pgpool())


@app.route('/')
async def index(req):
    # async with asyncpg.create_pool('postgres://postgres:ssdd@localhost:5433/tmp') as pgpool:   # this works fine
    async with pgpool.acquire() as conn:
        rs = await conn.fetchval('select 1')
        print('----', rs)
    return text('done')

app.run(port=8084)

error when curl http://127.0.0.1:8084

ERROR: Traceback (most recent call last):
  File "/usr/local/var/pyenv/versions/anaconda3-2.5.0/lib/python3.5/site-packages/sanic/sanic.py", line 329, in handle_request
    response = await response
  File "/Users/akc/project/py/tsweb/sweb.py", line 25, in index
    print('----', rs)
  File "/usr/local/var/pyenv/versions/anaconda3-2.5.0/lib/python3.5/site-packages/asyncpg/pool.py", line 252, in __aexit__
    await self.pool.release(con)
  File "/usr/local/var/pyenv/versions/anaconda3-2.5.0/lib/python3.5/site-packages/asyncpg/pool.py", line 184, in release
    await connection.reset()
  File "/usr/local/var/pyenv/versions/anaconda3-2.5.0/lib/python3.5/site-packages/asyncpg/connection.py", line 411, in reset
    ''')
  File "/usr/local/var/pyenv/versions/anaconda3-2.5.0/lib/python3.5/site-packages/asyncpg/connection.py", line 170, in execute
    return await self._protocol.query(query, timeout)
  File "asyncpg/protocol/protocol.pyx", line 249, in query (asyncpg/protocol/protocol.c:57280)
  File "asyncpg/protocol/protocol.pyx", line 354, in asyncpg.protocol.protocol.BaseProtocol._ensure_clear_state (asyncpg/protocol/protocol.c:59586)
asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress

@cctse what version of sanic are you using? It still looks like asyncpg and sanic are running a different loops.

@amsb
sanic 0.3.1
I think i found the problem, sanic tries to create the loop https://github.com/channelcat/sanic/blob/master/sanic/server.py#L295

Hey guys, I'm one of the maintainers of Sanic. Is there no way to pass a loop to asyncpg? You could use a server event to pass the loop sanic creates to asyncpg and establish the db connection like so.

Hey guys, I'm one of the maintainers of Sanic. Is there no way to pass a loop to asyncpg?

Both create_pool and Connection accept loop as argument.

That's what I thought. So it's really a non-issue here. Just a confusion on implementation.

Hey @seemethere, there was a time where Sanic supported passing a loop into the run command. After doing so searching, I've found that @1st1 has commented in Sanics issues about a common issue.

The problem maybe lies in the uvloop library?

There were a couple things I ran into while trying to utilize Sanic and asyncPG. You'll have to manually pass in a loop into Sanic. The problem being Sanic pulls a new loop out from asyncio. asyncio in turn calls get_event_loop_policy. uvloop as the default policy, returns a new event_loop while asyncio would return the a running event_loop

@jbcurtin Passing a loop was deprecated because event loops cannot be forked which makes it impossible to fully support multiprocessing.

As of python 3.6 asyncio.get_event_loop() returns the currently running event loop so there really shouldn't be any issues with getting the incorrect event loop unless you define a loop to use before you call app.run

Yes, I'm aware of those limitations. Take a look at the following...
https://github.com/channelcat/sanic/blob/master/sanic/app.py#L58
https://github.com/MagicStack/asyncpg/blob/master/asyncpg/connection.py#L556
https://github.com/MagicStack/uvloop/blob/master/uvloop/__init__.py#L22

I solved this by creating a GLOBAL setting that I run all my logic from. Sure, its a pain to manage, but I was able to move forward and fork the processes.

asyncio.set_event_loop_policy(uvloop.get_event_loop_policy())
EV_LOOP = asyncio.get_event_loop()
EV_LOOP.run_until_complete(...)

Unfortunately, the deprecation of Sanic supporting the loop like you mentioned has forced me to not upgrade until something is fixed.

hi @elprans ,
I got this error when running a simple aiohttp server for some simple tests on asyncpg,
prepared statment woks flawlessly while max concurrent connections to this server is just ONE,
but when it goes more than one, i.e, 2 or more , this error throws.
ab -c 1 -n 200 127.0.0.1:8000/ --> works fine
ab -c 2 -n 200 127.0.0.1:8000/ --> asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress

db_coro handler coroutine calls on every call of server :

async def db_coro(request):
    stmt= request.app['sql_prepared_stmt']
    print( await stmt.fetchval('Bob') )

Server main code:

if __name__ == '__main__':
    #Some simplecode for running simple aiohttp server
    app['sql_prepared_stmt'] = await conn.prepare('SELECT sid FROM test_tble WHERE name = $1 AND sid NOTNULL AND  sid >5')
    #Some simplecode for running simple aiohttp server

@Behzad-S seems like you are using a shared connection and are attempting to run queries concurrently on it. Use asyncpg.Pool and acquire/release a connection for each request.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HaithamMaya picture HaithamMaya  路  4Comments

samuelcolvin picture samuelcolvin  路  3Comments

iomintz picture iomintz  路  7Comments

inikolaev picture inikolaev  路  3Comments

mestrogov picture mestrogov  路  7Comments