lilydocs
HTTP APIWebSocketConsumer
Pipeline3 min read

Message lifecycle

Learn the order from route lookup to scope cleanup and how interruption changes the exit path.

One normal action is active per connection. The reader can queue complete application messages in a bounded queue and handle Ping, Pong, and Close frames without waiting for the action to finish. Different connections can invoke the same controller concurrently.

Normal order#

Message flow
Frame decode ve exact route lookup
  → DI scope and identity snapshot for the message
  → before_message: global → controller → action
  → guard: global → controller → action
  → all parts extractors → single payload consumer
  → action and response preparation
  → after_message: entered middleware in reverse order
  → scope cleanup and terminal result path

Unknown routes do not enter user message hooks. Queued messages do not yet own Scoped services or action tasks. Guards and the action see the same message's frozen Principal.

Policy plans#

Global policies come from the app builder; controller and action policies come from attributes. Repeating a concrete type in the same effective plan is a build error. Middleware plans are limited to 64 entries; that numerical limit does not apply to guard plans.

Instances are created once per concrete type per app. When sequential callbacks need state, use typed message locals or an appropriate scoped service instead of mutable instance fields. Context shows this transfer.

One normal deadline#

Before middleware, guards, extraction, the action, response preparation, and normal reverse exits share one absolute deadline. Each guard or after callback does not receive a fresh full duration. Action timeouts override the controller default, and controller timeouts override the app default.

Inbound waiting, transport writes, scope disposal, and termination cleanup have separate limits. The cooperation window on the deadline page does not restart the normal budget.

Exit on interruption#

Middleware whose before_message returns Continue counts as entered. This prefix normally exits in reverse order through after_message. If execution is interrupted, on_message_termination is available for entered middleware whose normal exit has not started or was interrupted.

A completed normal exit is not run again. Side effects of a partial exit are not automatically rolled back. Cleanup uses a separate CleanupCancellation; the callback does not rewrite the response. Do not assume the next message can safely begin before scope and task completion evidence is collected.

After understanding this order, add normal/termination callbacks through middleware and authorization decisions through guards.

Sources for this page v0.1.0

This guide is based on the reviewed framework commit.

QUICK START
Documentation
Source code