Files
portal/app/routes/console.php
T
Дмитрий fcd06afcb2 feat(supplier): retime supplier sync crons 20:30→18:00, 20:15→17:45
Запас ~3 часа до портального дедлайна 21:00 — эскалация на ярус 2/3
(медленный браузер / ручной оператор) происходит в рабочее время.
RefreshSupplierSessionJob daily — на 15 мин раньше sync (17:45).
Hourly RefreshSupplierSessionJob — без изменений.

Spec §4.7. Task 9 of 12. Tests 2/2 (cron expression + timezone).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 12:55:09 +03:00

63 lines
3.4 KiB
PHP

<?php
use App\Jobs\Supplier\CleanupInactiveSupplierProjectsJob;
use App\Jobs\Supplier\CsvReconcileJob;
use App\Jobs\Supplier\RefreshSupplierSessionJob;
use App\Jobs\Supplier\SyncSupplierProjectsJob;
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');
// Spec §6.1: ежедневный сброс projects.delivered_today=0 в 00:00 МСК.
// delivered_in_month НЕ трогаем — это месячный счётчик, отдельный cron Plan 4.
//
// NB: без `withoutOverlapping()` — операция идемпотентна (UPDATE WHERE delivered_today <> 0)
// и завершается за < 1 сек на любом ожидаемом объёме, overlap физически невозможен.
// Кроме того, `withoutOverlapping` требует таблицу `cache_locks`, которой в нашей
// schema.sql нет (Laravel-default-миграции удалены, см. project_state.md фаза 1).
Schedule::command('projects:reset-delivered-today')
->dailyAt('00:00')
->timezone('Europe/Moscow');
// Plan 4: monthly reset 1-го числа в 00:00 МСК для tier-lookup в LedgerService.
Schedule::command('projects:reset-monthly')
->monthlyOn(1, '00:00')
->timezone('Europe/Moscow');
// Audit #2 Phase 14 P2: partition maintenance — создаёт разделы на 3 месяца вперёд.
// Без этой записи partitions:create-months не запускается автоматически.
Schedule::command('partitions:create-months')
->daily()
->timezone('Europe/Moscow');
// Plan 3 Task 8: 5 Schedule entries для supplier-flow.
//
// NB: ->onOneServer() требует cache_locks таблицу, которой у нас нет
// (см. project_state.md фаза 1). Операции идемпотентны: SyncSupplierProjectsJob
// делает diff'ы (skip-no-diff), CleanupJob — UPDATE WHERE conditions, RefreshSession
// — Cache::lock guard внутри handle, RetryFailedSupplierJobs — WHERE retried_at
// фильтр. На multi-server prod может потребовать cache_locks таблицу.
Schedule::job(new RefreshSupplierSessionJob)->hourly();
// Spec docs/superpowers/specs/2026-05-19-supplier-project-channel-failover-design.md §4.7:
// крон переехал с 20:30 на 18:00 МСК — даёт ~3 часа окно восстановления
// (эскалация на медленный ярус 2 / ручной ярус 3) в рабочее время до
// портального дедлайна 21:00. Session refresh — на 15 мин раньше sync (17:45).
Schedule::job(new RefreshSupplierSessionJob)
->dailyAt('17:45')
->timezone('Europe/Moscow');
Schedule::job(new SyncSupplierProjectsJob)
->dailyAt('18:00')
->timezone('Europe/Moscow');
Schedule::job(new CleanupInactiveSupplierProjectsJob)
->dailyAt('02:00')
->timezone('Europe/Moscow');
Schedule::command('supplier:retry-failed')->hourly();
// Резервный CSV-канал (Путь 2): сверка каждые 30 минут.
// Spec: docs/superpowers/specs/2026-05-18-supplier-csv-reconcile-channel-design.md §4.5
Schedule::job(new CsvReconcileJob)->everyThirtyMinutes();