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

Walkthrough

Space play step click any line
Three takeaways
  1. 1Storing the window config in the cache lets you toggle maintenance without redeploying code.
  2. 2Content-negotiating the response keeps both browser users and API clients well informed.
  3. 3Combining an IP allowlist with a signed bypass token gives operators a safe escape hatch during maintenance.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A scheduled maintenance-window middleware in Laravel — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code