
Thrun: как я устал от Horizon и написал свой многопоточный воркер с корутинами
YanGusik 16 минут назад Thrun: как я устал от Horizon и написал свой многопоточный воркер с корутинами 8 мин 667 PHP * Laravel * Кейс Привет, меня зовут YanGusik. Я работал во многих PHP-проектах и в большинстве случаев...
Anthropic — What company has the best second artificial intelligence model at the end of June?
Вот важная новость с фронта ИИ: YanGusik 16 минут назад Thrun: как я устал от Horizon и написал свой многопоточный воркер с корутинами 8 мин 667 PHP * Laravel * Кейс Привет, меня зовут YanGusik. Я работал во многих PHP-проектах и в большинстве случаев в них использовался Horizon, Messenger, изредка RoadRunner. В одной компании был высоконагруженный сервис с большим количеством внешних API-запросов.
Сотни тысяч задач в очереди, каждая из которых делала несколько HTTP-запросов к внешним сервисам, ждала ответа, принимала решение, снова делала запрос. Типичная I/O-нагрузка. Поначалу всё крутилось на Laravel Horizon — стандартный выбор для Laravel-проектов.
Технические детали
Но чем больше рос проект, тем больше накапливались «мелкие» трения. Что раздражало в HorizonHorizon это зрелый, продуманный инструмент, но у него есть нюансы, которые в высоконагруженном проекте становятся настоящей болью: Мелкие, но утомляющиеtimeout — параметр-иллюзия. Если внутри job есть Http::timeout(60) или $client->request() с явным таймаутом, то реальное время выполнения job определяет HTTP-клиент, а не Horizon.
Формально timeout есть, фактически — job работает столько, сколько решит Guzzle. Это не баг, это особенность работы pcntl, но она неочевидна и ведёт к тому, что параметр timeout в конфиге создаёт ложное ощущение контроля. ShouldBeUnique без uniqueFor — тихая мина.
Если job зависнет и процесс упадёт, Redis-ключ уникальности останется вечно. Следующий dispatch молча проигнорируется — задача просто не встанет в очередь. Обнаруживается это обычно уже в продакшене, когда начинаешь разбираться почему данные не обновляются, а это очень критично для бизнеса.
Отраслевые последствия
retry_after меньше timeout — двойная обработка. Если retry_after меньше фактического времени выполнения job, задача будет взята в работу повторно, пока первая ещё не завершилась. Получаем одну задачу, обрабатываемую дважды.
Всё это решаемо: абстрактный базовый класс, документация, внимательность. Но в реальном проекте ты держишь это в голове постоянно, и это... Фундаментальные ограничения Масштабирование только через процессы.
I/O-bound задача занимает воркер на всё время ожидания HTTP-ответа. Единственный способ поднять throughput — добавить воркеры. Каждый воркер — отдельный PHP-процесс, отдельный контейнер Laravel, отдельные мегабайты RAM.
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





