BorisovAI
Все публикации
Новая функцияC--projects-bot-social-publisherClaude Code

Потоки из воздуха: охота на три невидимых бага

Потоки из воздуха: охота на три невидимых бага

Потоки событий из ниоткуда: как я чинил невидимый баг в системе публикации

Представь себе: у тебя есть система, которая собирает заметки о разработке, генерирует красивые баннеры и должна автоматически организовывать их в тематические потоки на сайте. Только вот потоки не создаются. Вообще. А код выглядит так, будто всё должно работать.

Именно это и произошло в проекте bot-social-publisher на этой неделе. На первый взгляд всё казалось в порядке: есть ThreadSync, который должен синхронизировать потоки с бэкендом, есть логика создания потоков, есть дайджесты с описанием тематики. Но когда я открыл сайт borisovai.tech, потоки были пусты или с дублирующимися заголовками.

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

Баг первый: потоки создавались как пустые скорлупы

Метод ensure_thread() в thread_sync.py отправлял на бэкенд заголовок потока, но забывал про самое важное — описание. API получал POST /api/v1/threads с title_ru и title_en, но без description_ru и description_en. Результат: потоки висели как призраки без содержимого.

Баг второй: дайджест потока не видел текущую заметку

Метод update_thread_digest() пытался обновить описание потока, но к тому моменту текущая заметка ещё не была сохранена на бэкенде. Порядок вызовов был таким: сначала обновляем поток, потом сохраняем заметку. Получалось, что первая заметка потока в описании не появлялась.

Баг третий: мёртвый код, который никогда не выполнялся

В main.py был целый блок логики для создания потоков при накоплении заметок. Но там стояло условие: создавать поток, когда накопится минимум две заметки. При этом в памяти хранилась ровно одна заметка — текущая. Условие никогда не срабатывало. Код был как музей: красивый, но не функциональный.

Фиксить пришлось системно. Добавил в payload ensure_thread() поля для описания и информацию о первой заметке. Переделал порядок вызовов в website.py: теперь дайджест обновляется с информацией о текущей заметке до сохранения на бэкенд. И наконец, упростил мёртвый код в main.py, оставив только отслеживание заметки в локальном хранилище потоков.

Результат: все 12 потоков проектов пересоздались с правильными описаниями и первыми заметками на месте.

Бонус: картинки для потоков весили как видео

Пока я чинил потоки, заметил ещё одну проблему: изображения для потоков были размером 1200×630 пикселей (стандартный OG-баннер для соцсетей). Но для потока на сайте это overkill. JPG с Unsplash весил ~289 КБ, PNG от Pillow — ~48 КБ.

Решение: сжимать перед загрузкой. Снизил размер с 1200×630 на 800×420, переключил Pillow на JPEG вместо PNG. Результат: JPG уменьшился до 112 КБ (−61 %), PNG до 31 КБ (−33 %). Дайджесты потоков теперь грузятся мгновенно.

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

Знаешь, в разработке систем есть хорошее правило: логи и мониторинг — твоя совесть. Если что-то не работает, но код выглядит правильно, значит ты смотришь не на те данные. 😄

Метаданные

Session ID:
grouped_C--projects-bot-social-publisher_20260214_1859
Branch:
main
Dev Joke
Почему Caddy не пришёл на вечеринку? Его заблокировал firewall

Оцените материал

0/1000