«Одна и та же яма — почему в неё можно упасть три раза? — хроника повторяющихся фиксов zidongjiexi (с системными уроками)»
Некоторые баги как подростковый возраст: тебе кажется, что всё прошло, а он просто сменит причёску и вернётся.
Эта авария вastrbot_plugin_zidongjiexiplusyoutubexiazai— типичный случай: кажется, что каждый раз “починили”, но при следующем перезапуске снова всё ломается.
I. Хронология инцидента: от «ошибки PIL» до «совместимости окружения»
Этап 1: первая ошибка (краш на загрузке ресурсов)
При запуске плагина в render.py на _load_video_button срабатывает:
img.convert("RGBA")- внутри Pillow —
AssertionError
Интуитивный вывод: в ресурсе media_button.png есть скрытый риск декодирования (возможно, изображение повреждено; возможно, различается путь/способ декодирования во время выполнения).
Этап 2: первый фикс (на вид успешно)
Сделали пересохранение ресурса (RGBA) — сразу после перезапуска всё заработало.
Отсюда легко сделать вывод «проблема решена».
Этап 3: рецидив (снова краш в том же месте)
После следующих перезапусков снова упало. Значит проблема не просто «файл однажды был битый», а:
- в самом кодовом пути нет отказоустойчивости;
- при разных состояниях выполнения плагин всё равно может ловить аналогичную ошибку декодирования.
Этап 4: во время второго фикса «фикс принёс новые проблемы»
При накатывании патча возникли две классические вторичные аварии:
- На уровне синтаксиса внесли ошибку (неаккуратная работа с комментариями/строками) →
SyntaxError; - Различия версий библиотек окружения привели к несовместимости параметров
EmojiCDNSource(параметрenable_tqdmне поддерживается).
В итоге сошлись через откат к стабильным файлам + минимальные инкрементальные изменения + проверку компиляции + валидацию перезапуском.
II. Анализ причин: почему «починили — и снова сломалось»
1) «Один раз успешно» ≠ «системно исправлено»
Пересохранить «битую» картинку — это устранить текущий экземпляр проблемы, но не гарантия, что в будущем не сработает тот же путь.
2) В коде плагина нет стратегии деградации для критических ресурсов
Ресурсы — внешняя зависимость. Внешняя зависимость должна быть «может упасть, но не смертельно».
3) Окружение выполнения не постоянно
Один и тот же плагин в разных контейнерных образах и при разных версиях зависимостей может инициализироваться по-разному.
Например, различия совместимости параметров apilmoji — это не ошибка бизнес-логики, а сцепление с версиями экосистемы.
4) В процессе фикса нет «жёстких шлюзов-ограничителей»
Если после каждого патча не делать сразу обязательные проверки ниже, легко откатиться из «запускается» в «падает по синтаксису»:
- синтаксическая проверка
py_compile - минимальная проверка холодного старта
- утверждение по ключевым логам загрузки плагина
III. Что именно сделала финальная правка
zidongjiexi
- Добавили отказоустойчивую логику в
_load_video_button:img.load()— принудительное раннее декодирование;- при исключении — деградация до прозрачной заглушки, чтобы не валить старт всего плагина.
- Убрали несовместимый параметр
enable_tqdmуEmojiCDNSource, чтобы подогнать под текущее окружение. - Многократной проверкой перезапуска подтвердили, что плагин стабильно переходит в состояние «загружен».
memelite (попутно починили)
- Исправили отсутствие
libEGL.so.1: установилиlibegl1/libgl1, убрали цикл восстановления зависимостей на старте.
IV. Почему перезапуск вырос с 20 секунд до 600+ секунд
Это не «машина внезапно стала медленной», а в цепочке старта появился блокирующий фактор:
- У
memeliteповторяющееся восстановление зависимостей + процесс pip растягивают запуск; - Повторные провалы загрузки плагина увеличивают общее время инициализации;
- Шторм ошибок в логах (включая аномалии формата логов сторонних библиотек) дополнительно усиливает ощущение «зависания».
По-человечески: не AstrBot за ночь постарел — он просто просыпается и одновременно чинит колесо.
V. Инженерные уроки (дороже самого фикса бага)
Урок 1: загрузка ресурсов должна «умирать, но позволять жить»
Картинки, шрифты, внешний CDN, cookie-файлы… нельзя предполагать, что они всегда в порядке.
Отказоустойчивость + деградация — нижняя граница сопровождаемости плагина.
Урок 2: фиксы должны идти по «замкнутому циклу минимальных изменений»
Рекомендуемый фиксированный процесс:
- Сначала вернуться к известной стабильной базе;
- Менять только одно место;
- Сделать синтаксическую/точечную проверку;
- Проверить перезапуском;
- Затем менять следующее место.
Урок 3: «починили» должно включать воспроизводимую проверку
«У меня заработало» не имеет значения — нужно, чтобы «всё ещё работает» выдерживало перезапуски и время.
Урок 4: при логировании остерегайтесь глобального сцепления формата
Если поля логов сторонней библиотеки не совпадают с форматом логов вашей системы, это может вызвать шум и даже мешать диагностике.
Можно выделить стороннему logger отдельный handler или понизить уровень логирования.
VI. Рекомендации на будущее (чтобы в следующий раз не повторилось)
- Добавить в плагин команду самопроверки при старте (проверка файлов ресурсов, версий зависимостей, ключевых конфигов);
- В CI или скрипт релиза добавить:
- синтаксическую проверку
- минимальный тест импорта
- smoke test ключевых функций инициализации
- Для «ресурсов некритичной функциональности» унифицировать стратегию деградации;
- Ввести «порог тревоги по времени перезапуска» (например, >90s — предупреждение) и автоматически собирать логи узких мест.
Заключение
Самое ценное в этом инциденте не «наконец-то починили», а то, что мы подтвердили:
- реально поставляемый фикс — это не разовый ручной пожарный выезд;
- а перевод системы из «запускается на удаче» в «запускается предсказуемо».
Если баги приходят собирать налог на интеллект, то в этот раз хотя бы чек сохранили.![]()