Request Lifecycle¶
Flow Diagram¶
graph TB
subgraph Octane["Laravel Octane v2 (Swoole/RoadRunner)"]
A["HTTP Request"] --> B["Per-request resets\nDisconnectFromDatabases\nFlushTemporaryContainerInstances\nCollectGarbage"]
end
B --> C["Global Middleware\nTrustProxies, HandleCors\nPreventRequestsDuringMaintenance"]
C --> D["CustomSession MW\nhighest priority (prepended)\nnamesapces cookie by surface"]
D --> E{Route surface}
E -->|"web routes"| F["user group\nEncryptCookies, AddQueuedCookies\nStartSession, ShareErrorsFromSession\nVerifyCsrfToken, SubstituteBindings\nEnsureGuestUser, HandleInertiaRequests\nAddLinkHeadersForPreloadedAssets"]
E -->|"admin routes"| G["web group\nEncryptCookies, AddQueuedCookies\nStartSession, HandleInertiaRequests\nSubstituteBindings"]
E -->|"api routes"| H["api group\nThrottleRequests, SubstituteBindings"]
E -->|"webhook routes"| I["api group\nno CSRF\nno session"]
F --> J["Route middleware\nauth/guest/verified\naddress_required\nproduct.is_private\nno-cache"]
J --> K["Controller (thin)\ndelegates immediately"]
K -->|"write"| L["Action class\nsingle-responsibility CQRS\nspatie/laravel-data DTO input"]
K -->|"query"| M["Manager class\nstateful coordinator\nQueryBuilder (9 modules)"]
L --> N["Eloquent Model\nMySQL / Redis"]
M --> N
N --> O{Response type}
O -->|"web (first visit)"| P["Inertia::render()\nVue3 page component\nfull HTML response"]
O -->|"web (XHR)"| Q["Inertia JSON response\npartial reload"]
O -->|"admin"| R["Blade view\n+ Inertia on admin pages"]
O -->|"api"| S["JSON response\nEloquent Resource"]
Purpose¶
Documents how a request travels from TCP socket to response under Octane's persistent-process model, including the complete middleware pipeline, delegation pattern, and Octane-specific risks.
Bootstrap Phase¶
Octane boots the Laravel application once per worker process, not per request. Per-request lifecycle:
- Worker receives HTTP request
- Octane fires per-request resets:
DisconnectFromDatabases— closes DB connections (prevents stale PDO state)FlushTemporaryContainerInstances— removes scoped bindingsCollectGarbage— runs GC cycle- Kernel handles request through middleware pipeline
- Response returned; worker ready for next request
No full bootstrap per request — static properties, singleton state, and Config::set() mutations persist across requests within the same worker.
Middleware Pipeline¶
Priority Override (Kernel)¶
CustomSession is prepended to $middlewarePriority — runs before all other middleware, including session middleware.
Global Middleware¶
All requests:
- TrustProxies
- HandleCors
- PreventRequestsDuringMaintenance
- ValidatePostSize
- TrimStrings
- ConvertEmptyStringsToNull
Route Groups (RouteServiceProvider)¶
| Group | Routes | Key Middleware |
|---|---|---|
user |
routes/web/* |
custom-session:user, EnsureGuestUser, HandleInertiaRequests, VerifyCsrfToken |
web (admin) |
routes/admin/* |
custom-session:admin, HandleInertiaRequests, VerifyCsrfToken |
api |
routes/api.php, routes/webhook.php |
ThrottleRequests, no CSRF, no session |
Named Route Middleware Aliases¶
| Alias | Class |
|---|---|
auth |
Authenticate |
auth:admin |
Authenticate (guard override) |
guest |
RedirectIfAuthenticated |
verified |
EnsureEmailIsVerified (custom) |
address_required |
AddressRequired |
custom-session:user |
CustomSession |
custom-session:admin |
CustomSession |
product.is_private |
EnsureProductIsPrivate |
no-cache |
Cache-Control headers |
CustomSession Detail¶
- Detects route path prefix to determine surface (web vs admin)
- Sets
config('session.cookie')to{name}_useror{name}_admin - Sets session lifetime (default for user, 480 min for admin)
Config::set()mutation on a singleton — Octane risk: config mutation persists to next request in same worker if middleware fails to run
Controller → Action/Manager Pattern¶
All controllers are thin — they validate input (Form Request) and delegate:
- Actions (
app/Modules/*/Actions/): single-responsibility CQRS-style units. Accept DTOs (spatie/laravel-data). Stateless, safe to use as singletons. - Managers (
app/Modules/*/Manager.php): stateful coordinators for multi-step operations (e.g.,OrderManager::storeOrder(),LotteryManager).
Custom QueryBuilders (9 modules)¶
| Module | QueryBuilder |
|---|---|
| Product | app/Modules/Product/QueryBuilders/ |
| ProductVariation | app/Modules/Product/QueryBuilders/ |
| Order | app/Modules/Order/QueryBuilders/ |
| OrderDetail | app/Modules/Order/QueryBuilders/ |
| Lottery | app/Modules/Lottery/QueryBuilders/ |
| Membership (User) | app/Modules/Membership/QueryBuilders/ |
| Cart | app/Modules/Cart/QueryBuilders/ |
| CkcCode | app/Modules/Chekicha/QueryBuilders/ |
| Sales | app/Modules/Sales/QueryBuilders/ |
Response Rendering¶
- Web (first visit):
Inertia::render('PageComponent', $props)→ full HTML + embedded JSON - Web (XHR/navigation): Inertia JSON response → Vue3 partial swap
- Admin pages: Inertia + Blade mix (admin uses Blade layout wrapping Inertia components)
- API:
JsonResource/ array response - View::composer: injects cart item count into all web views (one extra query per web request)
Octane-Specific Considerations¶
Config::set()mutation risk:CustomSessionmutatesconfig('session.cookie')— if a request panics after config mutation but before session is set, next request inherits wrong cookie name.- Static Action classes: safe — no instance state.
- Manager singletons: verify managers are not bound as singletons in module providers; user-specific state would leak between requests.
View::composercart count query: fires on every web request for authenticated users.- Worker crash recovery: Octane restarts crashed workers automatically; crashed worker state is discarded.
Failure Paths¶
| Failure | Behaviour |
|---|---|
VerifyCsrfToken mismatch |
419 → errors.419.blade.php |
Authenticate rejects |
Admin → admin.login, Order routes → login with return_to, all others → login |
EnsureEmailIsVerified |
Redirect to email verification notice |
AddressRequired |
Redirect to address form |
| Unhandled exception | Handler.php branches: admin → Inertia error page; web → Blade error views; API → JSON |
| Octane worker crash | Worker restarted; in-flight request dropped |