Dynamic Applications
Running Sanic has been optimized to work with the CLI. If you have not read it yet, you should read Running Sanic to become familiar with the options.
This includes running it as a global scope object...
sanic path.to.server:app
# server.py
app = Sanic("TestApp")
@app.get("/")
async def handler(request: Request):
return json({"foo": "bar"})
...or, a factory function that creates the Sanic
application object.
sanic path.to.server:create_app --factory
# server.py
def create_app():
app = Sanic("TestApp")
@app.get("/")
async def handler(request: Request):
return json({"foo": "bar"})
return app
Sometimes, this is not enough ... 🤔
Introduced in v22.9, Sanic has an AppLoader
object that is responsible for creating an application in the various worker processes. You can take advantage of this if you need to create a more dynamic startup experience for your application.
An AppLoader
can be passed a callable that returns a Sanic
instance. That AppLoader
could be used with the low-level application running API.
import sys
from functools import partial
from sanic import Request, Sanic, json
from sanic.worker.loader import AppLoader
def attach_endpoints(app: Sanic):
@app.get("/")
async def handler(request: Request):
return json({"app_name": request.app.name})
def create_app(app_name: str) -> Sanic:
app = Sanic(app_name)
attach_endpoints(app)
return app
if __name__ == "__main__":
app_name = sys.argv[-1]
loader = AppLoader(factory=partial(create_app, app_name))
app = loader.load()
app.prepare(port=9999, dev=True)
Sanic.serve(primary=app, app_loader=loader)
python path/to/server.py MyTestAppName
In the above example, the AppLoader
is created with a factory
that can be used to create copies of the same application across processes. When doing this, you should explicitly use the Sanic.serve
pattern shown above so that the AppLoader
that you create is not replaced.