php
59 lines · 7 steps
A scheduled maintenance-window middleware in Laravel
A middleware that blocks traffic during a cached deploy window while letting allowlisted clients and API callers through gracefully.
Explained by
highlit
1<?php
2
3namespace App\Http\Middleware;
4
5use Carbon\Carbon;
6use Closure;
7use Illuminate\Http\Request;
8use Illuminate\Support\Facades\Cache;
9use Symfony\Component\HttpFoundation\Response;
10
11class EnforceMaintenanceWindow
12{
13 public function handle(Request $request, Closure $next): Response
14 {
15 $window = Cache::get('deploy:maintenance_window');
16
17 if (! $window) {
18 return $next($request);
19 }
20
21 $now = Carbon::now();
22 $startsAt = Carbon::parse($window['starts_at']);
23 $endsAt = Carbon::parse($window['ends_at']);
24
25 if ($now->lt($startsAt) || $now->gt($endsAt)) {
26 return $next($request);
27 }
28
29 if ($this->isAllowed($request, $window)) {
30 return $next($request);
31 }
32
33 $retryAfter = $now->diffInSeconds($endsAt);
34
35 if ($request->expectsJson()) {
36 return response()->json([
37 'message' => $window['message'] ?? 'Service temporarily unavailable for scheduled maintenance.',
38 'retry_after' => $retryAfter,
39 'ends_at' => $endsAt->toIso8601String(),
40 ], Response::HTTP_SERVICE_UNAVAILABLE)->header('Retry-After', $retryAfter);
41 }
42
43 return response()
44 ->view('errors.maintenance', ['endsAt' => $endsAt], Response::HTTP_SERVICE_UNAVAILABLE)
45 ->header('Retry-After', $retryAfter);
46 }
47
48 protected function isAllowed(Request $request, array $window): bool
49 {
50 if (in_array($request->ip(), $window['allowed_ips'] ?? [], true)) {
51 return true;
52 }
53
54 $secret = $window['bypass_secret'] ?? null;
55
56 return $secret !== null && $request->hasValidSignature()
57 && hash_equals($secret, (string) $request->query('deploy_token'));
58 }
59}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Storing the window config in the cache lets you toggle maintenance without redeploying code.
- 2Content-negotiating the response keeps both browser users and API clients well informed.
- 3Combining an IP allowlist with a signed bypass token gives operators a safe escape hatch during maintenance.
Related explainers
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
javascript
import { useState, useEffect, useCallback, useRef } from 'react'; const cache = new Map(); const inflight = new Map();
Building a stale-while-revalidate hook in React
caching
request-deduplication
custom-hooks
Advanced
10 steps
php
<?php namespace App\Services;
Building a cached daily leaderboard in Laravel
caching
aggregation
eager-loading
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-scheduled-maintenance-window-middleware-in-laravel-explained-php-a319/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.