Resource Lifecycle & State

Updated Oct 15, 2026
  • on_connect(req, ws, **params) -> bool | None
  • Inspect headers and seed self.state; return False to reject the connection. The router runs after_connect hooks before it calls accept(). With receive_loop=True, it then begins receiving frames; with the default False, the application owns reception. If on_connect() sends a frame itself, call await ws.accept() first.
  • on_disconnect(ws, close_code) -> None
  • With WebSocketRouter(receive_loop=True), after on_connect permits the session, the router runs before_disconnect hooks and attempts this callback once, including failure in after_connect or accept. The code is the peer's code, or 1006 when it is missing or setup fails. Cancellation before cleanup starts closes with 1001 and propagates. If cancellation interrupts a peer-disconnect callback already in progress, it is not retried and retains the peer code, while the socket closes with 1001. Unexpected receive or handler failures close with 1011 and propagate the original exception. Rejected connections and failed on_connect calls do not run this lifecycle. With the default receive_loop=False, the application owns receive and cleanup.
  • With receive_loop=True, the router passes values returned by ws.receive_media() to WebSocketResource.dispatch() in order until the peer disconnects. Falcon may decode those values unless raw-frame media is enabled for the app.

For an attached router, attach() installs pass-through TEXT and BINARY deserializers in the application's shared ws_options.media_handlers mapping. For a manually mounted router, call configure_raw_frame_media(app) before Falcon constructs WebSockets. Both configure all WebSocket routes on the app, warn when replacing customized inbound handlers, and preserve the configured outgoing serializers. Falcon's default handlers decode input when neither entry point has enabled raw-frame handling.

  • self.state
  • Dict-like proxy shared across all resources in the same connection chain.
  • Override via get_child_context() to supply a custom state store (e.g., Redis-backed proxy).

Nested resources

class Parent(WebSocketResource):
    def __init__(self):
        self.state["parent_ready"] = True
        self.add_subroute("child/{item}", Child)

    def get_child_context(self):
        return {"project": "acme"}  # merged into child kwargs


class Child(WebSocketResource):
    def __init__(self, project: str):
        self.project = project

    async def on_connect(self, req, ws, item: str) -> bool:
        self.state["child_item"] = item
        return False
  • Path params flow into each resource; parent-provided context merges with params for the next child.
  • State defaults to a shared proxy unless overridden in get_child_context().