Ship production optimization M1-M12.5A: queues, metrics, HTTP observability, and vector search reliability.

Keep similar-ai from tripping the global circuit on a lone URL 502, clamp Qdrant search to 100, and add Server-Timing plus slow-request logging. Studio shared props, Academy S3 exists caching, heat chunking, and Redis/scheduler hygiene stay in this rollout.
This commit is contained in:
2026-08-25 07:58:47 +02:00
parent f52879edbb
commit 8a80aae21e
114 changed files with 9293 additions and 284 deletions
+43
View File
@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Negligible-overhead request duration header for production HTTP profiling.
* Does not log queries or payloads.
*/
final class AddServerTiming
{
public function handle(Request $request, Closure $next): Response
{
$started = hrtime(true);
$response = $next($request);
$durationMs = (hrtime(true) - $started) / 1_000_000;
if (headers_sent()) {
return $response;
}
$metrics = ['app;desc="Laravel";dur='.number_format($durationMs, 1, '.', '')];
$ssrMs = $request->attributes->get('http.ssr_ms');
if (is_numeric($ssrMs) && (float) $ssrMs >= 0) {
$metrics[] = 'ssr;desc="Inertia SSR";dur='.number_format((float) $ssrMs, 1, '.', '');
}
$metric = implode(', ', $metrics);
$existing = $response->headers->get('Server-Timing');
$response->headers->set(
'Server-Timing',
$existing ? $existing.', '.$metric : $metric,
);
return $response;
}
}
+10 -3
View File
@@ -98,6 +98,15 @@ final class HandleInertiaRequests extends Middleware
? $request->session()->get($key)
: null;
if ($user !== null && ! $user->relationLoaded('profile')) {
$user->load('profile');
}
$studioGroups = [];
if ($user !== null && str_starts_with($request->path(), 'studio')) {
$studioGroups = app(GroupService::class)->studioOptionsForUser($user);
}
return array_merge(parent::share($request), [
'auth' => [
'user' => $user ? [
@@ -134,9 +143,7 @@ final class HandleInertiaRequests extends Middleware
'group_assets' => (bool) config('features.group_assets', true),
'group_activity_feed' => (bool) config('features.group_activity_feed', true),
],
'studio_groups' => $user
? app(GroupService::class)->studioOptionsForUser($user)
: [],
'studio_groups' => $studioGroups,
]);
}
}
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use App\Support\Http\HttpUriNormalizer;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Inertia\Support\Header as InertiaHeader;
use Symfony\Component\HttpFoundation\Response;
final class LogSlowHttpRequest
{
public function __construct(private readonly HttpUriNormalizer $uris)
{
}
public function handle(Request $request, Closure $next): Response
{
if (! (bool) config('http_observability.slow_request.enabled', false)) {
return $next($request);
}
$started = hrtime(true);
$response = $next($request);
$durationMs = (hrtime(true) - $started) / 1_000_000;
if (app()->environment('testing')) {
$override = config('http_observability.slow_request.test_duration_ms');
if (is_numeric($override)) {
$durationMs = (float) $override;
}
}
$threshold = max(1, (int) config('http_observability.slow_request.threshold_ms', 750));
if ($durationMs < $threshold) {
return $response;
}
$route = $request->route();
$routeUri = is_object($route) && method_exists($route, 'uri')
? (string) $route->uri()
: $this->uris->normalize($request->path());
$payload = [
'time' => now()->toIso8601String(),
'method' => $request->getMethod(),
'route_name' => is_object($route) ? $route->getName() : null,
'route_uri' => $routeUri,
'status' => $response->getStatusCode(),
'duration_ms' => round($durationMs, 1),
'peak_memory_mb' => round(memory_get_peak_usage(true) / 1048576, 2),
'authenticated' => $request->user() !== null,
'inertia' => $this->isInertia($request, $response),
];
Log::channel('slow-http')->info(json_encode($payload, JSON_UNESCAPED_SLASHES));
return $response;
}
private function isInertia(Request $request, Response $response): bool
{
if ($request->headers->has(InertiaHeader::INERTIA)) {
return true;
}
return $response->headers->has(InertiaHeader::INERTIA)
|| $response->headers->get('Vary') === 'X-Inertia'
|| str_contains((string) $response->headers->get('Vary'), 'X-Inertia');
}
}
@@ -69,6 +69,11 @@ final class TrackOnlineVisitor
'email/*',
'logout',
'up',
'rss/*',
'rss-feeds',
'robots.txt',
'sitemap.xml',
'sitemaps/*',
])) {
return false;
}