Merge pull request #335 from r0fls/remove-loop

remove loop as argument and update examples
This commit is contained in:
Eli Uriegas 2017-01-27 19:25:09 -06:00 committed by GitHub
commit fad9fbca6f
10 changed files with 143 additions and 122 deletions

View File

@ -1,12 +1,8 @@
from sanic import Sanic from sanic import Sanic
from sanic.response import json from sanic.response import json
import uvloop
import aiohttp import aiohttp
#Create an event loop manually so that we can use it for both sanic & aiohttp
loop = uvloop.new_event_loop()
app = Sanic(__name__) app = Sanic(__name__)
async def fetch(session, url): async def fetch(session, url):
@ -24,10 +20,9 @@ async def test(request):
""" """
url = "https://api.github.com/repos/channelcat/sanic" url = "https://api.github.com/repos/channelcat/sanic"
async with aiohttp.ClientSession(loop=loop) as session: async with aiohttp.ClientSession() as session:
response = await fetch(session, url) response = await fetch(session, url)
return json(response) return json(response)
app.run(host="0.0.0.0", port=8000, loop=loop) app.run(host="0.0.0.0", port=8000, workers=2)

View File

@ -0,0 +1,36 @@
from sanic import Sanic
from sanic.response import json
import asyncio
import aiohttp
app = Sanic(__name__)
sem = None
def init(sanic, loop):
global sem
CONCURRENCY_PER_WORKER = 4
sem = asyncio.Semaphore(CONCURRENCY_PER_WORKER, loop=loop)
async def bounded_fetch(session, url):
"""
Use session object to perform 'get' request on url
"""
async with sem, session.get(url) as response:
return await response.json()
@app.route("/")
async def test(request):
"""
Download and serve example JSON
"""
url = "https://api.github.com/repos/channelcat/sanic"
async with aiohttp.ClientSession() as session:
response = await bounded_fetch(session, url)
return json(response)
app.run(host="0.0.0.0", port=8000, workers=2, before_start=init)

View File

@ -10,8 +10,6 @@ import aiopg
from sanic import Sanic from sanic import Sanic
from sanic.response import json from sanic.response import json
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
database_name = os.environ['DATABASE_NAME'] database_name = os.environ['DATABASE_NAME']
database_host = os.environ['DATABASE_HOST'] database_host = os.environ['DATABASE_HOST']
database_user = os.environ['DATABASE_USER'] database_user = os.environ['DATABASE_USER']
@ -21,45 +19,47 @@ connection = 'postgres://{0}:{1}@{2}/{3}'.format(database_user,
database_password, database_password,
database_host, database_host,
database_name) database_name)
loop = asyncio.get_event_loop()
async def get_pool(): async def get_pool():
return await aiopg.create_pool(connection) return await aiopg.create_pool(connection)
app = Sanic(name=__name__) app = Sanic(name=__name__)
pool = loop.run_until_complete(get_pool())
async def prepare_db():
""" Let's create some table and add some data
async def prepare_db(app, loop):
""" """
async with pool.acquire() as conn: Let's create some table and add some data
async with conn.cursor() as cur: """
await cur.execute('DROP TABLE IF EXISTS sanic_polls') async with aiopg.create_pool(connection) as pool:
await cur.execute("""CREATE TABLE sanic_polls ( async with pool.acquire() as conn:
id serial primary key, async with conn.cursor() as cur:
question varchar(50), await cur.execute('DROP TABLE IF EXISTS sanic_polls')
pub_date timestamp await cur.execute("""CREATE TABLE sanic_polls (
);""") id serial primary key,
for i in range(0, 100): question varchar(50),
await cur.execute("""INSERT INTO sanic_polls pub_date timestamp
(id, question, pub_date) VALUES ({}, {}, now()) );""")
""".format(i, i)) for i in range(0, 100):
await cur.execute("""INSERT INTO sanic_polls
(id, question, pub_date) VALUES ({}, {}, now())
""".format(i, i))
@app.route("/") @app.route("/")
async def handle(request): async def handle(request):
async with pool.acquire() as conn: result = []
async with conn.cursor() as cur: async def test_select():
result = [] async with aiopg.create_pool(connection) as pool:
await cur.execute("SELECT question, pub_date FROM sanic_polls") async with pool.acquire() as conn:
async for row in cur: async with conn.cursor() as cur:
result.append({"question": row[0], "pub_date": row[1]}) await cur.execute("SELECT question, pub_date FROM sanic_polls")
return json({"polls": result}) async for row in cur:
result.append({"question": row[0], "pub_date": row[1]})
res = await test_select()
return json({'polls': result})
if __name__ == '__main__': if __name__ == '__main__':
loop.run_until_complete(prepare_db()) app.run(host='0.0.0.0',
app.run(host='0.0.0.0', port=8000, loop=loop) port=8000,
debug=True,
before_start=prepare_db)

View File

@ -12,8 +12,6 @@ import sqlalchemy as sa
from sanic import Sanic from sanic import Sanic
from sanic.response import json from sanic.response import json
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
database_name = os.environ['DATABASE_NAME'] database_name = os.environ['DATABASE_NAME']
database_host = os.environ['DATABASE_HOST'] database_host = os.environ['DATABASE_HOST']
database_user = os.environ['DATABASE_USER'] database_user = os.environ['DATABASE_USER']
@ -23,8 +21,6 @@ connection = 'postgres://{0}:{1}@{2}/{3}'.format(database_user,
database_password, database_password,
database_host, database_host,
database_name) database_name)
loop = asyncio.get_event_loop()
metadata = sa.MetaData() metadata = sa.MetaData()
@ -34,40 +30,37 @@ polls = sa.Table('sanic_polls', metadata,
sa.Column("pub_date", sa.DateTime)) sa.Column("pub_date", sa.DateTime))
async def get_engine():
return await create_engine(connection)
app = Sanic(name=__name__) app = Sanic(name=__name__)
engine = loop.run_until_complete(get_engine())
async def prepare_db(): async def prepare_db(app, loop):
""" Let's add some data """ Let's add some data
""" """
async with engine.acquire() as conn: async with create_engine(connection) as engine:
await conn.execute('DROP TABLE IF EXISTS sanic_polls') async with engine.acquire() as conn:
await conn.execute("""CREATE TABLE sanic_polls ( await conn.execute('DROP TABLE IF EXISTS sanic_polls')
id serial primary key, await conn.execute("""CREATE TABLE sanic_polls (
question varchar(50), id serial primary key,
pub_date timestamp question varchar(50),
);""") pub_date timestamp
for i in range(0, 100): );""")
await conn.execute( for i in range(0, 100):
polls.insert().values(question=i, await conn.execute(
pub_date=datetime.datetime.now()) polls.insert().values(question=i,
) pub_date=datetime.datetime.now())
)
@app.route("/") @app.route("/")
async def handle(request): async def handle(request):
async with engine.acquire() as conn: async with create_engine(connection) as engine:
result = [] async with engine.acquire() as conn:
async for row in conn.execute(polls.select()): result = []
result.append({"question": row.question, "pub_date": row.pub_date}) async for row in conn.execute(polls.select()):
return json({"polls": result}) result.append({"question": row.question, "pub_date": row.pub_date})
return json({"polls": result})
if __name__ == '__main__': if __name__ == '__main__':
loop.run_until_complete(prepare_db()) app.run(host='0.0.0.0', port=8000, before_start=prepare_db)
app.run(host='0.0.0.0', port=8000, loop=loop)

View File

@ -10,8 +10,6 @@ from asyncpg import create_pool
from sanic import Sanic from sanic import Sanic
from sanic.response import json from sanic.response import json
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
DB_CONFIG = { DB_CONFIG = {
'host': '<host>', 'host': '<host>',
'user': '<username>', 'user': '<username>',
@ -21,45 +19,40 @@ DB_CONFIG = {
} }
def jsonify(records): def jsonify(records):
""" Parse asyncpg record response into JSON format """
Parse asyncpg record response into JSON format
""" """
return [{key: value for key, value in return [{key: value for key, value in
zip(r.keys(), r.values())} for r in records] zip(r.keys(), r.values())} for r in records]
loop = asyncio.get_event_loop()
async def make_pool():
return await create_pool(**DB_CONFIG)
app = Sanic(__name__) app = Sanic(__name__)
pool = loop.run_until_complete(make_pool())
async def create_db():
""" Create some table and add some data
async def create_db(app, loop):
""" """
async with pool.acquire() as connection: Create some table and add some data
async with connection.transaction(): """
await connection.execute('DROP TABLE IF EXISTS sanic_post') async with create_pool(**DB_CONFIG) as pool:
await connection.execute("""CREATE TABLE sanic_post ( async with pool.acquire() as connection:
id serial primary key, async with connection.transaction():
content varchar(50), await connection.execute('DROP TABLE IF EXISTS sanic_post')
post_date timestamp await connection.execute("""CREATE TABLE sanic_post (
);""") id serial primary key,
for i in range(0, 100): content varchar(50),
await connection.execute(f"""INSERT INTO sanic_post post_date timestamp
(id, content, post_date) VALUES ({i}, {i}, now())""") );""")
for i in range(0, 100):
await connection.execute(f"""INSERT INTO sanic_post
(id, content, post_date) VALUES ({i}, {i}, now())""")
@app.route("/") @app.route("/")
async def handler(request): async def handler(request):
async with pool.acquire() as connection: async with create_pool(**DB_CONFIG) as pool:
async with connection.transaction(): async with pool.acquire() as connection:
results = await connection.fetch('SELECT * FROM sanic_post') async with connection.transaction():
return json({'posts': jsonify(results)}) results = await connection.fetch('SELECT * FROM sanic_post')
return json({'posts': jsonify(results)})
if __name__ == '__main__': if __name__ == '__main__':
loop.run_until_complete(create_db()) app.run(host='0.0.0.0', port=8000, before_start=create_db)
app.run(host='0.0.0.0', port=8000, loop=loop)

View File

@ -9,19 +9,18 @@ from sanic import Sanic
from sanic.response import json from sanic.response import json
## peewee_async related imports ## peewee_async related imports
import uvloop
import peewee import peewee
from peewee_async import Manager, PostgresqlDatabase from peewee_async import Manager, PostgresqlDatabase
# we instantiate a custom loop so we can pass it to our db manager # we instantiate a custom loop so we can pass it to our db manager
loop = uvloop.new_event_loop()
database = PostgresqlDatabase(database='test', def setup(app, loop):
host='127.0.0.1', database = PostgresqlDatabase(database='test',
user='postgres', host='127.0.0.1',
password='mysecretpassword') user='postgres',
password='mysecretpassword')
objects = Manager(database, loop=loop) objects = Manager(database, loop=loop)
## from peewee_async docs: ## from peewee_async docs:
# Also theres no need to connect and re-connect before executing async queries # Also theres no need to connect and re-connect before executing async queries
@ -76,5 +75,4 @@ async def get(request):
if __name__ == "__main__": if __name__ == "__main__":
app.run(host='0.0.0.0', port=8000, loop=loop) app.run(host='0.0.0.0', port=8000, before_start=setup)

View File

@ -42,7 +42,6 @@ class Sanic:
self.response_middleware = deque() self.response_middleware = deque()
self.blueprints = {} self.blueprints = {}
self._blueprint_order = [] self._blueprint_order = []
self.loop = None
self.debug = None self.debug = None
self.sock = None self.sock = None
self.processes = None self.processes = None
@ -296,7 +295,6 @@ class Sanic:
:param sock: Socket for the server to accept connections from :param sock: Socket for the server to accept connections from
:param workers: Number of processes :param workers: Number of processes
received before it is respected received before it is respected
:param loop: asyncio compatible event loop
:param protocol: Subclass of asyncio protocol class :param protocol: Subclass of asyncio protocol class
:return: Nothing :return: Nothing
""" """
@ -319,7 +317,6 @@ class Sanic:
'error_handler': self.error_handler, 'error_handler': self.error_handler,
'request_timeout': self.config.REQUEST_TIMEOUT, 'request_timeout': self.config.REQUEST_TIMEOUT,
'request_max_size': self.config.REQUEST_MAX_SIZE, 'request_max_size': self.config.REQUEST_MAX_SIZE,
'loop': loop,
'register_sys_signals': register_sys_signals, 'register_sys_signals': register_sys_signals,
'backlog': backlog 'backlog': backlog
} }

View File

@ -289,7 +289,7 @@ def serve(host, port, request_handler, error_handler, before_start=None,
:param protocol: Subclass of asyncio protocol class :param protocol: Subclass of asyncio protocol class
:return: Nothing :return: Nothing
""" """
loop = loop or async_loop.new_event_loop() loop = async_loop.new_event_loop()
asyncio.set_event_loop(loop) asyncio.set_event_loop(loop)
if debug: if debug:

View File

@ -16,7 +16,7 @@ async def local_request(method, uri, cookies=None, *args, **kwargs):
def sanic_endpoint_test(app, method='get', uri='/', gather_request=True, def sanic_endpoint_test(app, method='get', uri='/', gather_request=True,
loop=None, debug=False, server_kwargs={}, debug=False, server_kwargs={},
*request_args, **request_kwargs): *request_args, **request_kwargs):
results = [] results = []
exceptions = [] exceptions = []
@ -36,7 +36,7 @@ def sanic_endpoint_test(app, method='get', uri='/', gather_request=True,
app.stop() app.stop()
app.run(host=HOST, debug=debug, port=PORT, app.run(host=HOST, debug=debug, port=PORT,
after_start=_collect_response, loop=loop, **server_kwargs) after_start=_collect_response, **server_kwargs)
if exceptions: if exceptions:
raise ValueError("Exception during request: {}".format(exceptions)) raise ValueError("Exception during request: {}".format(exceptions))

View File

@ -4,12 +4,20 @@ from sanic.utils import HOST, PORT
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest import pytest
import asyncio import asyncio
from queue import Queue
async def stop(app): async def stop(app, loop):
await asyncio.sleep(0.2) await asyncio.sleep(0.1)
app.stop() app.stop()
calledq = Queue()
def set_loop(app, loop):
loop.add_signal_handler = MagicMock()
def after(app, loop):
calledq.put(loop.add_signal_handler.called)
def test_register_system_signals(): def test_register_system_signals():
"""Test if sanic register system signals""" """Test if sanic register system signals"""
@ -19,11 +27,11 @@ def test_register_system_signals():
async def hello_route(request): async def hello_route(request):
return HTTPResponse() return HTTPResponse()
loop = asyncio.new_event_loop() app.run(HOST, PORT,
loop.add_signal_handler = MagicMock() before_start=set_loop,
asyncio.ensure_future(stop(app), loop=loop) after_start=stop,
app.run(HOST, PORT, loop=loop) after_stop=after)
assert loop.add_signal_handler.called == True assert calledq.get() == True
def test_dont_register_system_signals(): def test_dont_register_system_signals():
@ -34,8 +42,9 @@ def test_dont_register_system_signals():
async def hello_route(request): async def hello_route(request):
return HTTPResponse() return HTTPResponse()
loop = asyncio.new_event_loop() app.run(HOST, PORT,
loop.add_signal_handler = MagicMock() before_start=set_loop,
asyncio.ensure_future(stop(app), loop=loop) after_start=stop,
app.run(HOST, PORT, loop=loop, register_sys_signals=False) after_stop=after,
assert loop.add_signal_handler.called == False register_sys_signals=False)
assert calledq.get() == False