diff --git a/sanic/sanic.py b/sanic/sanic.py index 337c486a..3cfdaf4b 100644 --- a/sanic/sanic.py +++ b/sanic/sanic.py @@ -46,7 +46,6 @@ class Sanic: self._blueprint_order = [] self.debug = None self.sock = None - self.processes = None self.listeners = defaultdict(list) # Register alternative method names @@ -63,6 +62,22 @@ class Sanic: # Registration # -------------------------------------------------------------------- # + def add_task(self, task): + """ + Schedule a task to run later, after the loop has started. + Different from asyncio.ensure_future in that it does not + also return a future, and the actual ensure_future call + is delayed until before server start. + + :param task: A future, couroutine or awaitable. + """ + @self.listener('before_server_start') + def run(app, loop): + if callable(task): + loop.create_task(task()) + else: + loop.create_task(task) + # Decorator def listener(self, event): """ diff --git a/tests/test_create_task.py b/tests/test_create_task.py new file mode 100644 index 00000000..ff685620 --- /dev/null +++ b/tests/test_create_task.py @@ -0,0 +1,30 @@ +import sanic +from sanic.utils import sanic_endpoint_test +from sanic.response import text +from threading import Event +import asyncio + +def test_create_task(): + e = Event() + async def coro(): + await asyncio.sleep(0.05) + e.set() + + app = sanic.Sanic() + app.add_task(coro) + + @app.route('/early') + def not_set(request): + return text(e.is_set()) + + @app.route('/late') + async def set(request): + await asyncio.sleep(0.1) + return text(e.is_set()) + + + request, response = sanic_endpoint_test(app, uri='/early') + assert response.body == b'False' + + request, response = sanic_endpoint_test(app, uri='/late') + assert response.body == b'True'