2017-05-26 14:22:13 - (sanic)[ERROR]: Exception occurred while handling uri: "http://127.0.0.1:1230/write"
Traceback (most recent call last):
File "/home/sreenadh/Projects/Sanic_tests/hello/.hello/lib/python3.5/site-packages/sanic/app.py", line 471, in handle_request
response = await response
File "/usr/lib/python3.5/asyncio/coroutines.py", line 124, in throw
return self.gen.throw(exc)
File "app.py", line 18, in write_db
obj_id = await client.hello.write_col.save(data)
File "/usr/lib/python3.5/asyncio/futures.py", line 361, in __iter__
yield self # This tells Task to wait for completion.
RuntimeError: Task <Task pending coro=<Sanic.handle_request() running at /home/sreenadh/Projects/Sanic_tests/hello/.hello/lib/python3.5/site-packages/sanic/app.py:471> created at /home/sreenadh/Projects/Sanic_tests/hello/.hello/lib/python3.5/site-packages/sanic/server.py:185> got Future <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.5/asyncio/futures.py:431]> attached to a different loop
I have just started using Sanic, and I actually find it ver good, since am a big fan of Flask and simplicity that it gives. So I was following the same way as mentioned in the sanic_motor.py to test out writing some simple data from a POST request. i.e.:
def get_client():
from motor.motor_asyncio import AsyncIOMotorClient
client = AsyncIOMotorClient("mongodb://user:password@localhost:27045")
return client
.
.
.
@app.route('/write',methods=['POST'])
async def write_db(request):
data = request.json
client = get_client()
obj_id = await client.hello.write_col.save(data)
return response.json({ 'status':True, 'id':str(obj_id) })
Am I doing something wrong here?
Can anyone comment on this! :thinking:
Motor client need to use same ioloop as sanic. You can initialize ioloop by yourself or get it from framework.
Thanks for the quick reply :+1:
def get_client():
from motor.motor_asyncio import AsyncIOMotorClient
from sanic import app
client = AsyncIOMotorClient("mongodb://rootuser:passme123@localhost:27045",io_loop=app.get_event_loop())
return client
I changed the get_client() as this, and everything worked as expected. So is this the correct way?
Also, one doubt about calling the client function each time we need to access DB, is that a proper way to do it( I followed the example to test as such before digging around), or would it be better to define the client as a constant at the top along with app = Sanic(__name__)?
@sreecodeslayer I think it would be better to define constant at the top because it is calling it outside of the event loop.
Sitting inside a function handler that is.
Solution was provided and worked: https://github.com/channelcat/sanic/issues/749#issuecomment-304239758. Please close this issue.
I have tried the solution they comment but it is making connections all the time without reusing the previous ones, right?
It would not be easier to do this:
@app.listener('before_server_start')
def init(sanic, loop):
global db
from motor.motor_asyncio import AsyncIOMotorClient
mongo_uri = "mongodb://127.0.0.1:27017/test"
db = AsyncIOMotorClient(mongo_uri)['test']
So you can reuse the connection and the result of the requests is quite faster:
get_db()
Requests/sec: 580.71
Transfer/sec: 73.16KB
before_server_start
Requests/sec: 2174.00
Transfer/sec: 273.87KB
This is exactly the technique I was searching for. Solves my doubt regarding the efficiency of using the method over and over again.
Great one.
Would @kianxineki solutions work inside a blueprint scope? Like lets say I want to use the "db" object across blueprints so every blueprints can access a different database collection but doesn't need to create a new connection.
@andreheringer
I think I could do something similar to this:
models/__ init__.py
from motor.motor_asyncio import AsyncIOMotorClient
mongo_uri = "mongodb://127.0.0.1:27017/test"
db = AsyncIOMotorClient(mongo_uri)['database']
so you can do this anywhere
from models import db
does anyone on this thread have a public repo with some example code around this?
i have decent experience with node/express/mongo, but just new to python/sanic and some example code would be a big help to see some idiomatic patterns. any references appreciated!
@kianxineki would the above specifically need to use the io_loop trick from above like so?:
from motor.motor_asyncio import AsyncIOMotorClient
from sanic import app
mongo_uri = "mongodb://127.0.0.1:27017/test"
db = AsyncIOMotorClient(mongo_uri, io_loop=app.get_event_loop())['database']
from what i'm reading above, i thought motor need to be connected to sanic by event-loop and i don't see it in your sample, or are you making that "connection" elsewhere...?
__update__: nvm, i read this comment about get_event_loop in python 3.6 and how it will default to the running one. i kind of like explicitly passing via io_loop for clarity, but that's just me ;)
@tony-kerz
does anyone on this thread have a public repo with some example code around this?
I happen to have a repo that is quite old by now, you could still take a look at it Sanic Todo and relatively a new one, incomplete, having issues with Peewee and its orm. So its kinda dormant now.
Most helpful comment
@andreheringer
I think I could do something similar to this:
models/__ init__.py
so you can do this anywhere
from models import db