sanic-cors
sanic-cors copied to clipboard
SPF error when using Asyncio server instance
Following official documentation from Sanic , it is not possible to use CORS plugin with AsyncIO server instanciation.
Doing the following will provoke a crash, and server won't be able to process requests : "Error is SPF processing a request before App server is started."
import asyncio
import socket
import os
from sanic import Sanic
from sanic.response import json
from sanic_cors import CORS
app = Sanic(__name__)
CORS(app)
@app.route("/")
async def test(request):
return json({"hello": "world"})
server_socket = '/tmp/sanic.sock'
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove(server_socket)
finally:
sock.bind(server_socket)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
srv_coro = app.create_server(
sock=sock,
return_asyncio_server=True,
asyncio_server_kwargs=dict(
start_serving=False
)
)
srv = loop.run_until_complete(srv_coro)
try:
assert srv.is_serving() is False
loop.run_until_complete(srv.start_serving())
assert srv.is_serving() is True
loop.run_until_complete(srv.serve_forever())
except KeyboardInterrupt:
srv.close()
loop.close()
This is very similar to this bug: https://github.com/ashleysommer/sanicpluginsframework/issues/12 This is a SanicPluginsFramework issue, not specifically caused by Sanic-CORS.
This bug is triggered because starting Sanic in non-standard ways does not trigger the before_server_start
or after_server_start
events. So any listeners waiting for those events never get triggered. Another similar problem is mentioned in #47.
You can manually trigger the on_server_start
listener from Sanic-Plugins-Framework, you can use the same workaround that is mentioned in https://github.com/ashleysommer/sanicpluginsframework/issues/12#issuecomment-523238446
import asyncio
import socket
import os
from sanic import Sanic
from sanic.response import json
from sanic_cors import CORS
from spf import SanicPluginsFramework #<- this is added
app = Sanic(__name__)
spf = SanicPluginsFramework(app) #<- this is added
cors = spf.register_plugin(CORS) #<- this is changed
@app.route("/")
async def test(request):
return json({"hello": "world"})
server_socket = '/tmp/sanic.sock'
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove(server_socket)
finally:
sock.bind(server_socket)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
srv_coro = app.create_server(
sock=sock,
return_asyncio_server=True,
asyncio_server_kwargs=dict(
start_serving=False
)
)
srv = loop.run_until_complete(srv_coro)
try:
assert srv.is_serving() is False
spf._on_server_start(app, loop) #<- this is added
loop.run_until_complete(srv.start_serving())
assert srv.is_serving() is True
loop.run_until_complete(srv.serve_forever())
except KeyboardInterrupt:
srv.close()
loop.close()
Thanks for your quick answer, really appreciated. Would you suggest that I add documentation about this use case in this project or in Sanic ?
Documentation about this really should go in the Sanic Plugins Framework project.
The issue is caused by spf
not receiving signal that the app started up, and the solution is to manually trigger _on_server_start()
of the spf
object. However most people probably wouldn't immediately go to the SPF docs to read about about it if they're seeing this problem. It might be a documentation problem with Sanic, because the docs don't currently mention that this way of starting sanic might break plugins which expect Sanic to behave in a conventional way.
See this recent issue which is another side-effect of using the create_server()
method: https://github.com/huge-success/sanic/issues/1925