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
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Traffic;
use App\Services\Traffic\BotClassifier;
use App\Services\Traffic\OnlineVisitorRepository;
use Illuminate\Support\Facades\Redis;
use Tests\TestCase;
final class OnlineVisitorIndexReadTest extends TestCase
{
public function test_all_uses_sscan_and_never_smembers(): void
{
Redis::shouldReceive('sscan')
->once()
->andReturn([0, ['visitor-a', 'visitor-b']]);
Redis::shouldReceive('get')->twice()->andReturn(null);
Redis::shouldReceive('srem')->once();
Redis::shouldReceive('smembers')->never();
$repository = new OnlineVisitorRepository(app(BotClassifier::class));
$records = $repository->all();
$this->assertSame([], $records);
}
public function test_source_does_not_call_smembers_on_the_presence_index(): void
{
$source = file_get_contents(base_path('app/Services/Traffic/OnlineVisitorRepository.php'));
$this->assertNotFalse($source);
$this->assertStringNotContainsString('smembers', strtolower($source));
$this->assertStringContainsString('sscan', strtolower($source));
}
}
@@ -0,0 +1,73 @@
<?php
use App\Services\Traffic\OnlineVisitorRepository;
use App\Services\Traffic\PresenceIndexPruner;
use Illuminate\Support\Facades\Redis;
it('removes stale presence members and keeps live ones', function () {
Redis::shouldReceive('sscan')->once()->andReturn([0, ['stale-1', 'live-1']]);
Redis::shouldReceive('pipeline')->once()->andReturnUsing(function ($cb) {
$pipe = Mockery::mock();
$pipe->shouldReceive('exists')->twice();
$cb($pipe);
return [0, 1];
});
Redis::shouldReceive('eval')->once()->andReturn(1);
$result = app(PresenceIndexPruner::class)->prune(200, 1, 10, 0, false);
expect($result['scanned'])->toBe(2)
->and($result['stale'])->toBe(1)
->and($result['live'])->toBe(1)
->and($result['removed'])->toBe(1);
});
it('dry-run counts stale members without srem/eval', function () {
Redis::shouldReceive('sscan')->once()->andReturn([0, ['stale-1']]);
Redis::shouldReceive('pipeline')->once()->andReturnUsing(function ($cb) {
$pipe = Mockery::mock();
$pipe->shouldReceive('exists')->once();
$cb($pipe);
return [0];
});
Redis::shouldReceive('eval')->never();
$result = app(PresenceIndexPruner::class)->prune(200, 5, 100, 0, true);
expect($result['stale'])->toBe(1)
->and($result['removed'])->toBe(0)
->and($result['dry_run'])->toBeTrue();
});
it('respects max-batches and max-members', function () {
Redis::shouldReceive('sscan')->once()->andReturn([1, ['a', 'b']]);
Redis::shouldReceive('pipeline')->once()->andReturnUsing(function ($cb) {
$pipe = Mockery::mock();
$pipe->shouldReceive('exists')->twice();
$cb($pipe);
return [0, 0];
});
Redis::shouldReceive('eval')->never();
$result = app(PresenceIndexPruner::class)->prune(200, 1, 2, 0, true);
expect($result['batches'])->toBe(1)
->and($result['scanned'])->toBe(2);
});
it('does not use smembers on the presence index', function () {
$source = file_get_contents(base_path('app/Services/Traffic/PresenceIndexPruner.php'));
expect(strtolower((string) $source))->not->toContain('smembers')
->and(strtolower((string) $source))->toContain('sscan');
});
it('never deletes the presence index key', function () {
$source = (string) file_get_contents(base_path('app/Services/Traffic/PresenceIndexPruner.php'));
expect($source)->toContain('SREM')
->and($source)->not->toContain('unlink')
->and($source)->not->toContain('->del(')
->and($source)->not->toContain('FLUSH');
});