Anatomi Insiden: Blind Spot Health Check dan Conditional Shared Props
Pada arsitektur monolit modern dengan Inertia.js (misalnya Laravel + Vue/React), navigasi browser awal (full page load) dan navigasi internal (SPA visit) diperlakukan berbeda oleh middleware HandleInertiaRequests. Request SPA selalu menyertakan header HTTP X-Inertia: true dan mengharapkan respons berupa payload JSON, bukan dokumen HTML.
Insiden umum terjadi saat deployment bertahap (rolling update) ketika ada pembaruan kode pada method share() di middleware. Jika shared props mengeksekusi dependensi baru—seperti kolom database yang belum termigrasi penuh atau pembacaan cache session dengan skema baru—kegagalan runtime hanya terpicu saat request memuat header X-Inertia: true.
// app/Http/Middleware/HandleInertiaRequests.php
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'auth.user' => fn () => $request->user()
? $request->user()->only('id', 'name', 'tenant_tier') // Kolom 'tenant_tier' belum ada di DB production
: null,
'notifications_count' => fn () => $request->user()
? $request->user()->unreadNotifications()->count()
: 0,
]);
}Blind spot muncul karena liveness dan readiness probe standar dari Kubernetes atau AWS Target Group biasanya hanya memanggil endpoint GET /healthz atau root GET / tanpa header Inertia. Request probe ini mengembalikan status 200 OK karena tidak mengeksekusi logika shared props Inertia, atau mengembalikan kerangka Blade statis. Akibatnya, orkestrator menandai pod baru sebagai sehat, meneruskan seluruh trafik pengguna, dan memicu error 500 massal pada navigasi SPA klien.
Observabilitas: Memisahkan Metrik X-Inertia vs Request Standar
Untuk mendeteksi kegagalan parsial ini secara instan, sistem monitoring harus membedakan metrik trafik reguler dan trafik SPA Inertia. Tanpa pemisahan ini, lonjakan error 500 tenggelam di dalam agregasi total HTTP error.
1. Tagging Log Kontekstual
Inject metadata request langsung ke context logger via middleware kustom atau hook global framework:
// app/Http/Middleware/TagInertiaRequestContext.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class TagInertiaRequestContext
{
public function handle(Request $request, Closure $next)
{
$isInertia = $request->header('X-Inertia') === 'true';
Log::withContext([
'is_inertia' => $isInertia,
'inertia_version' => $request->header('X-Inertia-Version', 'none'),
]);
return $next($request);
}
}2. Instrumentasi Metrik Prometheus dan Sentry
Kirimkan label spesifik pada metrik penghitung HTTP Prometheus:
# Metrik Prometheus: http_requests_total
http_requests_total{method="GET",path="/dashboard",status="500",inertia="true"} 142
http_requests_total{method="GET",path="/dashboard",status="200",inertia="false"} 520Pada Sentry, tambahkan tag inertia_request ke global scope agar alert rule dapat mendeteksi kegagalan rendering props sebelum komplain pengguna masuk:
\Sentry\configureScope(function (\Sentry\State\Scope $scope) use ($request): void {
$scope->setTag('inertia_request', $request->header('X-Inertia') === 'true' ? 'true' : 'false');
});Prosedur Auto-Rollback Berbasis Metrik Ingress
Deployment otomatis harus dilengkapi mekanisme fail-safe yang membaca lonjakan error rate khusus request Inertia. Menggunakan Prometheus metrics bersama controller canary deployment (seperti Argo Rollouts atau Flagger), definisikan ambang batas ketat.
Kriteria Threshold Rollback
- Metric: Error rate (5xx) pada request dengan label
inertia="true". - Window Analysis: 1 menit hingga 2 menit interval.
- Failure Threshold: > 1% dari total request Inertia selama evaluasi berjalan.
Contoh Analisis Argo Rollouts (PromQL)
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: inertia-error-rate-check
spec:
metrics:
- name: inertia-5xx-rate
interval: 30s
successCondition: result[0] < 0.01
failureLimit: 2
provider:
prometheus:
address: http://prometheus-server.monitoring.svc:9090
query: |
sum(rate(http_requests_total{inertia="true",status=~"5.."}[1m]))
/
(sum(rate(http_requests_total{inertia="true"}[1m])) > 0 or vector(1))Jika canary deployment merilis replika baru yang menyebabkan runtime failure pada HandleInertiaRequests, metrik langsung melebihi 0.01 (1%), memicu pembatalan rollout seketika dan mengembalikan routing ingress ke revisi pod lama yang stabil.
Simulasi Postmortem: Timeline dan Root Cause Analysis
Berikut ringkasan evaluasi insiden kegagalan deployment middleware Inertia:
- 14:02 UTC: CI/CD memicu rolling update revisi
v2.14.0. Pipeline migration berjalan paralel tetapi mengalami lock timeout pada tabeltenants. - 14:04 UTC: Pod
v2.14.0aktif. Kubelet menjalankan HTTP probe ke/healthz. Status respons200 OK. Pod ditandaiReady. - 14:05 UTC: Ingress mulai mengirimkan 25% trafik produksi ke pod baru. Klien SPA yang melakukan navigasi internal mengirim
X-Inertia: trueke endpoint/app/*. - 14:05:30 UTC:
HandleInertiaRequests::share()gagal mengeksekusi lazy-property karena skema DB belum siap. Error 500 terjadi pada seluruh navigasi SPA. - 14:06:15 UTC: Prometheus merekam lonjakan
inertia=true, status=500hingga 18%. - 14:07:00 UTC: Automated rollback terpicu oleh sistem CD. Traffic dialihkan 100% kembali ke
v2.13.9. Layanan normal.
Root Cause: Dependensi data baru dieksekusi langsung di jalur shared props global tanpa pengecekan ketersediaan skema (defensive checking), diperparah oleh probe Kubernetes yang tidak mensimulasikan headers komunikasi Inertia.
Pencegahan: Implementasi Synthetic Probe Inertia
Solusi pencegahan permanen adalah menyelaraskan health probe orkestrator dengan arsitektur SPA. Modifikasi probe bawaan agar mensimulasikan permintaan Inertia secara penuh.
Konfigurasi Kubernetes Readiness Probe dengan Custom Headers
readinessProbe:
httpGet:
path: /healthz/inertia
port: 8080
httpHeaders:
- name: X-Inertia
value: "true"
- name: X-Inertia-Version
value: "synthetic-probe"
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 2Endpoint Verifikasi Khusus
Buat rute pengujian internal yang melewati seluruh middleware pipeline, termasuk HandleInertiaRequests:
// routes/web.php
Route::get('/healthz/inertia', function () {
return Inertia::render('HealthCheck', [
'status' => 'ok',
'timestamp' => now()->toIso8601String(),
]);
})->middleware(['web', 'inertia']);Dengan memvalidasi payload JSON dan evaluasi shared props pada fase readiness check, setiap regresi runtime di level middleware akan menahan pod baru dalam status NotReady, mencegah pod menerima trafik publik, dan menghentikan deployment sebelum insiden terjadi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!