aio-libs / aiohttp-devtools

dev tools for aiohttp

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

devtools can not work with session[aioredis]

ipfans opened this issue · comments

  • aiohttp-devtools version:
    0.6.4
  • aiohttp version:
    2.3.4
  • python version:
    3.6.3
  • Platform:
    OSX

Issue Summary

Starting with adev runserver simple.py will raise RuntimeError: This event loop is already running but it works for python simple.py

Code Example

#simple.py
from aiohttp import web
import asyncio
import aioredis
from aiohttp_session import setup, get_session
from aiohttp_session.redis_storage import RedisStorage


async def create_redis_pool():
    return await aioredis.create_pool(('127.0.0.1', 6379))


def setup_sessions(app, pool):
    storage = RedisStorage(pool)
    setup(app, storage)


async def index(request):
    sess = await get_session(request)
    last_visit = sess['last_visit'] if 'last_visit' in sess else "never"
    sess['last_visit'] = "yes"
    return web.Response(text=last_visit)


def create_app():
    loop = asyncio.get_event_loop()
    pool = loop.run_until_complete(create_redis_pool())
    app = web.Application()
    setup_sessions(app, pool)
    app.router.add_get("/", index)
    return app


if __name__ == '__main__':
    web.run_app(create_app(), port=8000)

Steps to reproduce

  1. adev runserver simple.py.
  2. check out error message.

This is not an error, this is you not using aiohttp correctly.

Look at onstartup.

I already tried signal on aiohttp before I opened this issue, but it raised another error. This code snippet is from demo of aiohttp-session, and it should be works. Of course, both versions are working fine on python simple.py command. So I think it caused by adev command.

e.x.

# simple.py
from aiohttp import web
import asyncio
import aioredis
from aiohttp_session import setup, get_session
from aiohttp_session.redis_storage import RedisStorage


async def create_redis_pool():
    return await aioredis.create_pool(('127.0.0.1', 6379))


async def setup_sessions(app):
    pool = await create_redis_pool()
    storage = RedisStorage(pool)
    setup(app, storage)


async def index(request):
    sess = await get_session(request)
    last_visit = sess['last_visit'] if 'last_visit' in sess else "never"
    sess['last_visit'] = "yes"
    return web.Response(text=last_visit)


def create_app():
    app = web.Application()
    app.on_startup.append(setup_sessions)
    app.router.add_get("/", index)
    return app


if __name__ == '__main__':
    web.run_app(create_app(), port=8000)

traceback:

$ adev runserver simple.py
[21:13:29] pre-check enabled, checking app factory
[21:13:29] Starting aux server at http://localhost:8001 ◆
[21:13:29] Starting dev server at http://localhost:8000 ●
Process Process-1:
Traceback (most recent call last):
  File "/Users/user/.pyenv/versions/3.6.3/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/Users/user/.pyenv/versions/3.6.3/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp_devtools/runserver/serve.py", line 124, in serve_main_app
    loop.run_until_complete(app.startup())
  File "/Users/user/.pyenv/versions/3.6.3/lib/python3.6/asyncio/base_events.py", line 467, in run_until_complete
    return future.result()
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp/web.py", line 264, in startup
    yield from self.on_startup.send(self)
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp/signals.py", line 51, in send
    yield from self._send(*args, **kwargs)
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp/signals.py", line 17, in _send
    yield from res
  File "/Users/user/Developer/projects/new/simple.py", line 16, in setup_sessions
    setup(app, storage)
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp_session/__init__.py", line 158, in setup
    app.middlewares.append(session_middleware(storage))
AttributeError: 'tuple' object has no attribute 'append'

Humm, for me this is a result of the dumb way aiohttp-sessions is setup.

I'll try to make a pull request there to fix how it works. In the meantime you can avoid this issue with --no-pre-check, eg. run adev runserver --no-pre-check session_demo.py.

Sorry to be curt early, main of the issues here are just simple questions about usage.

@samuelcolvin I also tried disable pre-check at first time, but it also not work for me.

$ adev runserver --no-pre-check simple.py
[21:40:34] Starting aux server at http://localhost:8001 ◆
[21:40:34] Starting dev server at http://localhost:8000 ●
Process Process-1:
Traceback (most recent call last):
  File "/Users/user/.pyenv/versions/3.6.3/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/Users/user/.pyenv/versions/3.6.3/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp_devtools/runserver/serve.py", line 124, in serve_main_app
    loop.run_until_complete(app.startup())
  File "/Users/user/.pyenv/versions/3.6.3/lib/python3.6/asyncio/base_events.py", line 467, in run_until_complete
    return future.result()
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp/web.py", line 264, in startup
    yield from self.on_startup.send(self)
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp/signals.py", line 51, in send
    yield from self._send(*args, **kwargs)
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp/signals.py", line 17, in _send
    yield from res
  File "/Users/user/Developer/projects/new/simple.py", line 16, in setup_sessions
    setup(app, storage)
  File "/Users/user/.local/share/virtualenvs/new-y2QdrW3f/lib/python3.6/site-packages/aiohttp_session/__init__.py", line 158, in setup
    app.middlewares.append(session_middleware(storage))
AttributeError: 'tuple' object has no attribute 'append'

Use the first snippet, not the second.

If you look in setup it just adds middleware which you can't do once the app is frozen, so you can't call it in a startup coroutine.

@samuelcolvin My first snippet is a problem that adev runs a ioloop, I can not use run_until_complete to call async func. But I also can not find another way to init aioreids pool before app is frozen. Maybe I am not found a right way to use a blocking coroutine call, because callback often called after app frozen.

I think it maybe two ways to fix this:

  1. When call create_app, adev should stop asyncio loop.(It seems that will be a big project.)
  2. Support create_app func to be a coroutine. (I am trying this.)
(env) aiohttp-devtools 0 174ms ➤  echo "THIS IS COPIED VERBATIM FROM THE FIRST SNIPPET IN YOUR ISSUE!"
THIS IS COPIED VERBATIM FROM THE FIRST SNIPPET IN YOUR ISSUE!
(env) aiohttp-devtools 0 164ms ➤  cat session_demo.py 
from aiohttp import web
import asyncio
import aioredis
from aiohttp_session import setup, get_session
from aiohttp_session.redis_storage import RedisStorage


async def create_redis_pool():
    return await aioredis.create_pool(('127.0.0.1', 6379))


def setup_sessions(app, pool):
    storage = RedisStorage(pool)
    setup(app, storage)


async def index(request):
    sess = await get_session(request)
    last_visit = sess['last_visit'] if 'last_visit' in sess else "never"
    sess['last_visit'] = "yes"
    return web.Response(text=last_visit)


def create_app():
    loop = asyncio.get_event_loop()
    pool = loop.run_until_complete(create_redis_pool())
    app = web.Application()
    setup_sessions(app, pool)
    app.router.add_get("/", index)
    return app


if __name__ == '__main__':
    web.run_app(create_app(), port=8000)
(env) aiohttp-devtools 0 2.04s ➤  adev runserver --no-pre-check session_demo.py 
[13:54:12] Starting aux server at http://localhost:8001 ◆
[13:54:12] Starting dev server at http://localhost:8000 ●
[13:54:14] ● GET / 200 233B
[13:54:14] ● GET / 200 233B
[13:54:14] ● GET / 200 233B
^C[13:54:16] shutting down server...
(env) aiohttp-devtools 0 5.24s ➤  

Is your behaviour different to this?

@samuelcolvin I checked my history, it seems that disable pre-check is OK. Sorry about that.