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:
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\Artwork;
|
||||
use App\Services\Vision\AiArtworkVectorSearchService;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
uses(\Illuminate\Foundation\Testing\RefreshDatabase::class);
|
||||
|
||||
beforeEach(function (): void {
|
||||
config()->set('vision.vector_gateway.enabled', true);
|
||||
config()->set('vision.vector_gateway.base_url', 'https://vision.klevze.net');
|
||||
config()->set('vision.vector_gateway.api_key', 'test-key');
|
||||
config()->set('vision.vector_gateway.search_endpoint', '/vectors/search');
|
||||
config()->set('vision.vector_gateway.search_file_endpoint', '/vectors/search/file');
|
||||
config()->set('cdn.files_url', 'https://files.skinbase.org');
|
||||
Storage::fake('public');
|
||||
Cache::flush();
|
||||
});
|
||||
|
||||
function limitSourceArtwork(): Artwork
|
||||
{
|
||||
return Artwork::factory()->create([
|
||||
'title' => 'Limit source',
|
||||
'hash' => 'aabbccddeeff',
|
||||
'thumb_ext' => 'webp',
|
||||
'is_public' => true,
|
||||
'is_approved' => true,
|
||||
'published_at' => now()->subHour(),
|
||||
]);
|
||||
}
|
||||
|
||||
function fakeFileSearchOk(): void
|
||||
{
|
||||
Http::fake(function ($request) {
|
||||
$url = $request->url();
|
||||
if (str_contains($url, '/vectors/search')) {
|
||||
return Http::response(['results' => []], 200);
|
||||
}
|
||||
|
||||
return Http::response('image-bytes', 200, ['Content-Type' => 'image/webp']);
|
||||
});
|
||||
}
|
||||
|
||||
function gatewaySearchLimit($request): ?int
|
||||
{
|
||||
$url = $request->url();
|
||||
if (! str_contains($url, '/vectors/search')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = $request->data();
|
||||
if (isset($data['limit']) && is_numeric($data['limit'])) {
|
||||
return (int) $data['limit'];
|
||||
}
|
||||
|
||||
foreach ($data as $part) {
|
||||
if (is_array($part) && ($part['name'] ?? null) === 'limit' && is_numeric($part['contents'] ?? null)) {
|
||||
return (int) $part['contents'];
|
||||
}
|
||||
}
|
||||
|
||||
$body = $request->body();
|
||||
if (preg_match('/name="limit".*?\r\n\r\n(\d+)/s', $body, $matches) === 1) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
if (preg_match('/"limit"\s*:\s*([0-9]+)/', $body, $matches) === 1) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
it('sends gateway limit 100 when similar-ai is requested at 99', function (): void {
|
||||
$source = limitSourceArtwork();
|
||||
fakeFileSearchOk();
|
||||
|
||||
app(AiArtworkVectorSearchService::class)->similarToArtwork($source, 99);
|
||||
|
||||
Http::assertSent(fn ($request): bool => gatewaySearchLimit($request) === 100);
|
||||
});
|
||||
|
||||
it('clamps similar-ai requests of 100 and 120 so the gateway never sees more than 100', function (): void {
|
||||
$source = limitSourceArtwork();
|
||||
|
||||
foreach ([100, 120, 121] as $requested) {
|
||||
fakeFileSearchOk();
|
||||
Cache::flush();
|
||||
|
||||
app(AiArtworkVectorSearchService::class)->similarToArtwork($source, $requested);
|
||||
|
||||
Http::assertSent(fn ($request): bool => gatewaySearchLimit($request) === 100);
|
||||
}
|
||||
});
|
||||
|
||||
it('sends gateway limit 13 for the default similar-ai request of 12', function (): void {
|
||||
$source = limitSourceArtwork();
|
||||
fakeFileSearchOk();
|
||||
|
||||
app(AiArtworkVectorSearchService::class)->similarToArtwork($source, 12);
|
||||
|
||||
Http::assertSent(fn ($request): bool => gatewaySearchLimit($request) === 13);
|
||||
});
|
||||
|
||||
it('clamps uploaded-image search to 100 without adding an extra candidate', function (): void {
|
||||
fakeFileSearchOk();
|
||||
|
||||
app(AiArtworkVectorSearchService::class)->searchByUploadedImage(
|
||||
UploadedFile::fake()->image('query.png', 32, 32),
|
||||
120,
|
||||
);
|
||||
|
||||
Http::assertSent(fn ($request): bool => gatewaySearchLimit($request) === 100);
|
||||
});
|
||||
Reference in New Issue
Block a user