Files
portal/app/tests/Feature/Autopodbor/AutopodborQueueThrottleTest.php
T
Дмитрий 43e29823a8 perf(autopodbor): разнести шаги по очередям — find (ИИ) и study (тупой слой)
Раньше поиск, резолв и изучение делили одну очередь autopodbor — при одном
воркере быстрый шаг 2 (изучение) стоял за тяжёлым шагом 1 (поиск с ИИ) другого
клиента. Теперь два процесса:
  • шаг 1 «собрать поле» (поиск + резолв по имени, ИИ+внешние) → autopodbor-find
  • шаг 2 «дайте источники / изучение» (без ИИ) → autopodbor-study
Идут параллельно, друг друга не держат. Замок WithoutOverlapping по runId цел.

Запуск теперь двумя воркерами:
  queue:work redis --queue=autopodbor-find  --timeout=3600
  queue:work redis --queue=autopodbor-study --timeout=3600

TDD: AutopodborQueueThrottleTest 4/4, автоподбор 434/434.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 15:28:51 +03:00

47 lines
2.2 KiB
PHP

<?php
declare(strict_types=1);
use App\Jobs\Autopodbor\RunAutopodborResolveJob;
use App\Jobs\Autopodbor\RunAutopodborSearchJob;
use App\Jobs\Autopodbor\RunAutopodborStudyJob;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Support\Facades\Queue;
// Масштаб: два шага разнесены по РАЗНЫМ очередям (разные процессы-воркеры), чтобы не толкались.
// Шаг 1 «собрать поле» с ИИ (поиск + резолв по имени) → очередь autopodbor-find.
// Шаг 2 «изучение / дайте источники» — тупой слой → очередь autopodbor-study.
// Так быстрый шаг 2 одного клиента не стоит за тяжёлым шагом 1 другого.
// Плюс защита от нахлёста (WithoutOverlapping) на случай ретрая/повторного dispatch.
it('шаг 1 (поиск) уходит на очередь autopodbor-find', function () {
Queue::fake();
RunAutopodborSearchJob::dispatch(123);
Queue::assertPushedOn('autopodbor-find', RunAutopodborSearchJob::class);
});
it('резолв по имени — тоже шаг 1, на очереди autopodbor-find', function () {
Queue::fake();
RunAutopodborResolveJob::dispatch(8);
Queue::assertPushedOn('autopodbor-find', RunAutopodborResolveJob::class);
});
it('шаг 2 (изучение) уходит на ОТДЕЛЬНУЮ очередь autopodbor-study', function () {
Queue::fake();
RunAutopodborStudyJob::dispatch(7);
Queue::assertPushedOn('autopodbor-study', RunAutopodborStudyJob::class);
});
it('все три задания защищены от нахлёста — middleware WithoutOverlapping по runId', function () {
expect((new RunAutopodborSearchJob(123))->middleware())->toHaveCount(1)
->and((new RunAutopodborSearchJob(123))->middleware()[0])->toBeInstanceOf(WithoutOverlapping::class)
->and((new RunAutopodborStudyJob(7))->middleware()[0])->toBeInstanceOf(WithoutOverlapping::class)
->and((new RunAutopodborResolveJob(8))->middleware()[0])->toBeInstanceOf(WithoutOverlapping::class);
});