• Здесь буду писать о своих проектах, иногда разбирать интересные технические штуки, делиться рабочими наблюдениями и складывать мемы, без которых айти почему-то до сих пор не научилось существовать.

    Без обещаний «уникального контента каждый день» и прочей ярмарки тщеславия. Просто то, что мне самому интересно делать, изучать и обсуждать.

    Спасибо, что заглянули ^_^

    Здесь буду писать о своих проектах, иногда разбирать интересные технические штуки, делиться рабочими наблюдениями и складывать мемы, без которых айти почему-то до сих пор не научилось существовать.

    Без обещаний «уникального контента каждый день» и прочей ярмарки тщеславия. Просто то, что мне самому интересно делать, изучать и обсуждать.

    Спасибо, что заглянули ^_^


  • Иногда идея для отдельного open source пакета появляется не из желания придумать что-нибудь новое, а ровно наоборот: начинаешь разбирать старый проект и находишь там решение, которое когда-то было нормальным, а теперь уже мешает двигаться дальше.


    Так получилось с моим старым symfony-shop

    Во время модернизации проекта я добрался до авторизации через Яндекс. Она была реализована через пакет rakeev/oauth2-yandex. Сам по себе подход был вполне обычным: вместо того чтобы самостоятельно реализовывать весь OAuth 2.0 flow, приложение использовало готовый провайдер.

    Проблема была в возрасте зависимости

    Последние изменения в rakeev/oauth2-yandex относятся ещё к 2017 году. За это время PHP, библиотеки вокруг него и инструменты разработки заметно изменились. При тестировании обновлённого приложения старая зависимость уже начала напоминать о себе предупреждениями и долго, когда deprecated перейдет в error 

    И здесь было несколько вариантов


    Самый быстрый: убрать пакет и написать необходимый код прямо внутри symfony-shop. Для одного проекта это вполне рабочее решение. Несколько классов, немного настройки, авторизация снова работает — задача закрыта.

    Но у такого подхода есть очевидный минус: решение остаётся внутри конкретного приложения.

    Если завтра авторизация через Яндекс понадобится в другом проекте, всё начинается заново.

    Можно было пойти в другую сторону и попытаться оживить старый пакет. Но мне хотелось получить небольшое современное решение с понятной зоной ответственности и без необходимости тащить за собой архитектурные решения проекта восьмилетней давности.

    Поэтому появился третий вариант — сделать отдельный пакет.


    Иногда идея для отдельного open source пакета появляется не из желания придумать что-нибудь новое, а ровно наоборот: начинаешь разбирать старый проект и находишь там решение, которое когда-то было нормальным, а теперь уже мешает двигаться дальше.


    Так получилось с моим старым symfony-shop

    Во время модернизации проекта я добрался до авторизации через Яндекс. Она была реализована через пакет rakeev/oauth2-yandex. Сам по себе подход был вполне обычным: вместо того чтобы самостоятельно реализовывать весь OAuth 2.0 flow, приложение использовало готовый провайдер.

    Проблема была в возрасте зависимости

    Последние изменения в rakeev/oauth2-yandex относятся ещё к 2017 году. За это время PHP, библиотеки вокруг него и инструменты разработки заметно изменились. При тестировании обновлённого приложения старая зависимость уже начала напоминать о себе предупреждениями и долго, когда deprecated перейдет в error 

    И здесь было несколько вариантов


    Самый быстрый: убрать пакет и написать необходимый код прямо внутри symfony-shop. Для одного проекта это вполне рабочее решение. Несколько классов, немного настройки, авторизация снова работает — задача закрыта.

    Но у такого подхода есть очевидный минус: решение остаётся внутри конкретного приложения.

    Если завтра авторизация через Яндекс понадобится в другом проекте, всё начинается заново.

    Можно было пойти в другую сторону и попытаться оживить старый пакет. Но мне хотелось получить небольшое современное решение с понятной зоной ответственности и без необходимости тащить за собой архитектурные решения проекта восьмилетней давности.

    Поэтому появился третий вариант — сделать отдельный пакет.


  • Laravel выпустил 13.26, и среди изменений мне особенно понравился DebounceFor для queued listeners.

    Смысл простой: если одно и то же событие прилетает много раз подряд, можно не запускать пачку почти одинаковых задач, а немного подождать и обработать уже финальное состояние.

    Простой пример: в админке несколько раз подряд меняют один и тот же товар — название, цену, описание, потом ещё что-то поправляют. Без такой логики в очередь могут улететь несколько одинаковых обновлений поискового индекса. Хотя по факту нужен только результат последнего изменения.

    Что здесь происходит

    1


    DebounceFor(30): Laravel ждёт 30 секунд после последнего события. Если за это время приходит ещё одно такое же событие, отсчёт начинается заново.

    maxWait: 120: ограничивает общее ожидание двумя минутами. Даже если события продолжают сыпаться без остановки, актуальная задача всё равно получит возможность выполниться максимум через 120 секунд с начала этой серии.

    debounceId(): нужен, чтобы Laravel понимал, какие события объединять. В примере используется ID товара, поэтому изменения одного товара группируются вместе, а другого — отдельно.

    Разумеется, debounce существовал как концепция задолго до Laravel 13.26.

    И при необходимости такую механику никто не мешал написать самостоятельно: кеш, блокировки, таймеры, идентификаторы, обработка граничных случаев. А теперь для типового случая есть понятная встроенная механика.

    Не самая громкая фича Laravel 13.26, зато вполне практичная 😉


    Laravel выпустил 13.26, и среди изменений мне особенно понравился DebounceFor для queued listeners.

    Смысл простой: если одно и то же событие прилетает много раз подряд, можно не запускать пачку почти одинаковых задач, а немного подождать и обработать уже финальное состояние.

    Простой пример: в админке несколько раз подряд меняют один и тот же товар — название, цену, описание, потом ещё что-то поправляют. Без такой логики в очередь могут улететь несколько одинаковых обновлений поискового индекса. Хотя по факту нужен только результат последнего изменения.

    Что здесь происходит

    1


    DebounceFor(30): Laravel ждёт 30 секунд после последнего события. Если за это время приходит ещё одно такое же событие, отсчёт начинается заново.

    maxWait: 120: ограничивает общее ожидание двумя минутами. Даже если события продолжают сыпаться без остановки, актуальная задача всё равно получит возможность выполниться максимум через 120 секунд с начала этой серии.

    debounceId(): нужен, чтобы Laravel понимал, какие события объединять. В примере используется ID товара, поэтому изменения одного товара группируются вместе, а другого — отдельно.

    Разумеется, debounce существовал как концепция задолго до Laravel 13.26.

    И при необходимости такую механику никто не мешал написать самостоятельно: кеш, блокировки, таймеры, идентификаторы, обработка граничных случаев. А теперь для типового случая есть понятная встроенная механика.

    Не самая громкая фича Laravel 13.26, зато вполне практичная 😉