I'm planing to run an aiohttp production server using:
Client Request ----> Nginx (Reverse-Proxy) + Gunicorn
|
\
`-> App. Server I. 127.0.0.1:8081
I'm getting all sorts of errors, but one that I can't figure out is this:
File "/Users/yad/pySites/Slog/venv/lib/python3.5/site-packages/aiohttp/worker.py", line 65, in make_handler
"aiohttp.wsgi is not supported anymore, "
RuntimeError: aiohttp.wsgi is not supported anymore, consider to switch to aiohttp.web.Application
According to the documents, running the gunicorn with this line should be fine:
gunicorn aiohttp-server:main --bind localhost:3000 --worker-class aiohttp.GunicornWebWorker
Any suggestions?
I tried following the documentation for these details
you can use aiohttp 1.3 version, it supports wsgi.
wsgi is not supported by aiohttp 2.0
Thanks @fafhrd91! Is it in the plan for the new version or it's fully dropped?
Do you have any recommendation for deployment? Like a guide or so?
I'm having a hard time understanding how I can run the aiohttp apps with Gunicorn and WSGI.
Currently I have:
aiohttp-server.py >> file
contnet:
import json
import asyncio
import logging
from aiohttp import web
from functools import wraps
# imports...
class Rest:
@asyncio.coroutine
def index(self, request):
return web.Response(body=b"Hello, world")
@rest_handler
@asyncio.coroutine
def log(self, request):
#... doing some more work here:
print("request arrived")
return ""
def main():
rest = Rest()
app = web.Application()
app.router.add_route('GET', '/', rest.index)
app.router.add_route('POST', '/log', rest.log)
loop = asyncio.get_event_loop()
handler = app.make_handler()
f = loop.create_server(handler, '0.0.0.0', 3000)
srv = loop.run_until_complete(f)
log.info('serving on %r', srv.sockets[0].getsockname())
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
log.info('\nBye')
loop.run_until_complete(handler.finish_connections(1.0))
srv.close()
loop.run_until_complete(srv.wait_closed())
loop.run_until_complete(app.finish())
loop.close()
if __name__ == '__main__':
main()
now when I run:
gunicorn aiohttp-server:main --bind localhost:3000 --worker-class aiohttp.GunicornWebWorker
I get this:
[2017-05-08 17:14:59 -0700] [81259] [INFO] Starting gunicorn 19.7.1
[2017-05-08 17:14:59 -0700] [81259] [INFO] Listening at: http://127.0.0.1:3000 (81259)
[2017-05-08 17:14:59 -0700] [81259] [INFO] Using worker: aiohttp.GunicornWebWorker
[2017-05-08 17:14:59 -0700] [81259] [INFO] Unhandled exception in main loop
Traceback (most recent call last):
File "/Users/yad/pySites/Slog/venv/lib/python3.5/site-packages/gunicorn/arbiter.py", line 202, in run
self.manage_workers()
File "/Users/name/pySites/MyProject/venv/lib/python3.5/site-packages/gunicorn/arbiter.py", line 544, in manage_workers
self.spawn_workers()
File "/Users/name/pySites/MyProject/venv/lib/python3.5/site-packages/gunicorn/arbiter.py", line 611, in spawn_workers
self.spawn_worker()
File "/Users/name/pySites/MyProject/venv/lib/python3.5/site-packages/gunicorn/arbiter.py", line 564, in spawn_worker
self.cfg, self.log)
TypeError: 'str' object is not callable
aiohttp.readthedocs.io/en/1.3.5/
But I'd suggest to use aiohttp.web framework instead of wsgi
Oh, sorry. You are using aiohttp.web
So, to use gunicorn you need point it to application object and you don't need any of run_ methods. Gunicorn worker does it for you
Check "Start gunicorn" section
Thanks again @fafhrd91 for the help, the issue was the unicorn worker name:
i used this at firstaiohttp.GunicornWebWorker, but it should be aiohttp.worker.GunicornWebWorker for the 1.3 version
Now, I'm getting this error:
2017-05-08 18:37:28 -0700] [82090] [INFO] Starting gunicorn 19.7.1
[2017-05-08 18:37:28 -0700] [82090] [INFO] Listening at: http://127.0.0.1:3000 (82090)
[2017-05-08 18:37:28 -0700] [82090] [INFO] Using worker: aiohttp.worker.GunicornWebWorker
[2017-05-08 18:37:28 -0700] [82097] [INFO] Booting worker with pid: 82097
INFO:root:serving on ('0.0.0.0', 3000)
[2017-05-08 18:37:58 -0700] [82090] [CRITICAL] WORKER TIMEOUT (pid:82097)
INFO:root:
Bye
[2017-05-08 18:37:58 -0700] [82097] [INFO] Worker exiting (pid: 82097)
Exception ignored in: <bound method BaseEventLoop.__del__ of <_UnixSelectorEventLoop running=False closed=True debug=False>>
Traceback (most recent call last):
File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/asyncio/base_events.py", line 431, in __del__
File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/asyncio/unix_events.py", line 58, in close
File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/asyncio/unix_events.py", line 139, in remove_signal_handler
File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/signal.py", line 47, in signal
TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
[2017-05-08 18:37:58 -0700] [82122] [INFO] Booting worker with pid: 82122
INFO:root:serving on ('0.0.0.0', 3000)
[2017-05-08 18:38:28 -0700] [82090] [CRITICAL] WORKER TIMEOUT (pid:82122)
INFO:root:
Bye
[2017-05-08 18:38:28 -0700] [82122] [INFO] Worker exiting (pid: 82122)
Exception ignored in: <bound method BaseEventLoop.__del__ of <_UnixSelectorEventLoop running=False closed=True debug=False>>
Traceback (most recent call last):
I will look into this and might bother you later in another issue :)
could you post your code?
thank you very much!
aiohttp-server.py
import json
import asyncio
import logging
from aiohttp import web
from functools import wraps
from pymongo import MongoClient
import os
# Mongo setup:
client = MongoClient(os.getenv('MongoDBURL'))
db = client['logs']
logging.basicConfig(level=logging.INFO)
log = logging.getLogger()
def rest_handler(handler_func):
"""
Allows handlers to return dict.
Errors are handled and put in json format.
"""
@wraps(handler_func)
def wrapper(self, request):
error_code = None
try:
res = yield from handler_func(self, request)
result = dict(status='OK', result=res)
except web.HTTPClientError as e:
log.warning('Http error: %r %r', e.status_code, e.reason,
exc_info=True)
error_code = e.status_code
result = dict(error_code=error_code,
error_reason=e.reason,
status='FAILED')
except Exception as e:
log.warning('Server error', exc_info=True)
error_code = 500
result = dict(error_code=error_code,
error_reason='Unhandled exception',
status='FAILED')
assert isinstance(result, dict)
body = json.dumps(result).encode('utf-8')
result = web.Response(body=body)
result.headers['Content-Type'] = 'application/json'
if error_code:
result.set_status(error_code)
return result
return wrapper
class Rest:
@asyncio.coroutine
def index(self, request):
return web.Response(body=b"Hello, world")
@rest_handler
@asyncio.coroutine
def log(self, request):
data = yield from request.post()
# Get the Log Type to write to proper Mongo Collection / DB
collection = db[dict(data)['col_name']]
data_inserted = json.loads(json.dumps(dict(data)))
# Data Inserted to Database here:
response = collection.insert_one(data_inserted)
# print(response.inserted_id)
log.info('Message reveived %r', data_inserted)
return ""
# def main():
rest = Rest()
app = web.Application()
app.router.add_route('GET', '/', rest.index)
app.router.add_route('POST', '/log', rest.log)
loop = asyncio.get_event_loop()
handler = app.make_handler()
f = loop.create_server(handler, '0.0.0.0', 3000)
srv = loop.run_until_complete(f)
log.info('serving on %r', srv.sockets[0].getsockname())
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
log.info('\nBye')
loop.run_until_complete(handler.finish_connections(1.0))
srv.close()
loop.run_until_complete(srv.wait_closed())
loop.run_until_complete(app.finish())
loop.close()
# if __name__ == '__main__':
# main()
Python 3.5.2gunicorn version_info': (19, 7, 1)Then I run this:
gunicorn aiohttp-server:app --bind localhost:3000 --worker-class aiohttp.worker.GunicornWebWorker
and I get the above error:
Could it be: the Port issue localhost to 0.0.0.0 ?
I have been following this guide to deploy the AIOHTTP + WSGI + Gunicorn, and that might be an issue as well. Since I wasn't sure how to connect the Gunicorn to NginX directly.
you don need to run loop in your script gunicorn worker does it.
here is slightly modified script, you can read mongo.
import json
import asyncio
import logging
from aiohttp import web
from functools import wraps
import os
logging.basicConfig(level=logging.INFO)
log = logging.getLogger()
def rest_handler(handler_func):
"""
Allows handlers to return dict.
Errors are handled and put in json format.
"""
@wraps(handler_func)
def wrapper(self, request):
error_code = None
try:
res = yield from handler_func(self, request)
result = dict(status='OK', result=res)
except web.HTTPClientError as e:
log.warning('Http error: %r %r', e.status_code, e.reason,
exc_info=True)
error_code = e.status_code
result = dict(error_code=error_code,
error_reason=e.reason,
status='FAILED')
except Exception as e:
log.warning('Server error', exc_info=True)
error_code = 500
result = dict(error_code=error_code,
error_reason='Unhandled exception',
status='FAILED')
assert isinstance(result, dict)
body = json.dumps(result).encode('utf-8')
result = web.Response(body=body)
result.headers['Content-Type'] = 'application/json'
if error_code:
result.set_status(error_code)
return result
return wrapper
class Rest:
@asyncio.coroutine
def index(self, request):
return web.Response(body=b"Hello, world")
@rest_handler
@asyncio.coroutine
def log(self, request):
data = yield from request.post()
# Get the Log Type to write to proper Mongo Collection / DB
collection = db[dict(data)['col_name']]
data_inserted = json.loads(json.dumps(dict(data)))
# Data Inserted to Database here:
response = collection.insert_one(data_inserted)
# print(response.inserted_id)
log.info('Message reveived %r', data_inserted)
return ""
# def main():
rest = Rest()
app = web.Application()
app.router.add_route('GET', '/', rest.index)
app.router.add_route('POST', '/log', rest.log)
your gunicorn command will work:
gunicorn aiohttp-server:app --bind localhost:3000 --worker-class aiohttp.worker.GunicornWebWorker
That worked like a charm buddy! Thanks for the tips, your framework is awesome :)
thanks!
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a [new issue] for
related bugs.
If you feel like there's important points made in this discussion,
please include those exceprts into that [new issue].
Most helpful comment
you can use aiohttp 1.3 version, it supports wsgi.
wsgi is not supported by aiohttp 2.0