Содержание урока · 10 разделов
До сих пор очередь отвечала вам кодом: срез GetQueueInfo, списки ListRetryTasks, ручные операции Inspector. Это форма для скриптов и алертов, но прод-инструменты смотрят не только инженеры: дежурному нужны ответы в три ночи, тестировщик хочет увидеть свою задачу глазами, продукт оценивает длину бэклога. Для них существует asynqmon — веб-инструмент мониторинга и администрирования очередей asynq: не только графики, но и кнопки действий над задачами. Это отдельный проект: он подключается к тому же Redis, на котором живёт библиотека, и переводит внутренние структуры в страницы браузера. Числа на экране совпадают с Inspector из пятнадцатого урока один в один: читаются одни и те же ключи Redis, поэтому расхождений между скриптом и asynqmon ui не бывает — бывает разное время среза. В Go-программу добавлять нечего: дашборд читает Redis напрямую и запускается отдельно от воркеров. В этом уроке поднимем его в Docker, пройдём вкладки семи состояний от active до aggregating, найдём графики обработок и ошибок и соберём сценарий отладки лагов: от тикета «письма стоят» до конкретной застрявшей задачи и её ручного запуска кнопкой.
Asynqmon ui: запуск в Docker#
Asynqmon распространяется готовым docker-образом hibiken/asynqmon, и запуск занимает одну команду: docker run --rm -p 8080:8080 hibiken/asynqmon — по адресу localhost:8080 открывается интерфейс без единой строчки в вашем Go-коде. По умолчанию контейнер ищет Redis на localhost:6379; если база живёт в соседнем контейнере или на другой машине, адрес передаётся переменной окружения REDIS_URL в формате redis://host:6379, номер базы — переменной REDIS_DB. Список флагов и переменных время от времени уточняется, поэтому сверяйте его с README репозитория asynqmon: проект живёт независимо от библиотеки и развивается своим ритмом, версии образа и версии go-пакета могут расходиться — обмен идёт через ключи Redis, а не через общий релиз. Второй типовой способ — docker-compose, где дашборд ставят рядом с Redis и воркерами: сервис asynqmon получает имя соседа в REDIS_URL и слушает порт 8080. Главное правило подключения: asynqmon должен смотреть в тот же Redis, что и ваши воркеры. Если он подключится к пустой базе dev-окружения, перед вами будет спокойный пустой интерфейс, за которым ничего не происходит, — и это не мониторинг, а обман зрения. Как только адрес совпал, интерфейс показывает все очереди, которые видит в Redis, со счётчиками по состояниям и графиками — к ним перейдём после вкладок.
Запуск образа asynqmon
GOdocker run --rm -p 8080:8080 hibiken/asynqmon
# Redis на другой машине или в другом контейнере:
docker run --rm -p 8080:8080 \
-e REDIS_URL=redis://db.internal:6379 \
hibiken/asynqmonОдна команда без переменных годится для локального Redis: порт 8080 контейнера проброшен на тот же порт хоста, интерфейс откроется в браузере. REDIS_URL указывает asynqmon на тот же Redis, где живёт asynq; флаг --rm убирает контейнер после остановки. Флаги и переменные образа обновляются вместе с проектом — сверяйте их с README asynqmon.
Вкладки asynq дашборда: семь состояний#
Язык asynq дашборда — семь состояний задачи, и каждое живёт на своей вкладке; вы уже знаете их по ретраям и отложкам, теперь они станут вкладками. Pending — задача поставлена и ждёт свободного воркера. Active — хендлер исполняется прямо сейчас: строка живёт ровно столько, сколько работает обработка, постоянных жителей у вкладки нет, поэтому пустой active — норма между тиками. Scheduled — отложенные постановки ProcessIn и периодические тики. Retry — падавшие задачи с временем следующей попытки. Archived — конечная станция исчерпанных попыток и фатальных ошибок. Completed — успешные задачи, оставшиеся после работы, и здесь самое частое недоумение новичка: вкладка пустая, хотя система исправно шлёт письма. Так и задумано: без опции Retention успешная задача удаляется сразу после успеха; записываться в completed она станет только там, где постановка попросила Retention(d), и пролежит на вкладке до истечения срока. Aggregating — задачи, ждущие сборки в группах: вкладка отвечает на вопрос «копится ли пачка» одним взглядом. Ценность вкладок — арифметика симптомов: растущий retry при плоском active указывает на внешние сбои, копящийся aggregating — на остановившуюся сборку пачек, длинный scheduled при пустом pending — на обещания, которые вы дали сами опциями постановки. Таблица ниже — шпаргалка по этим семи вкладкам: где задача появляется и на что смотреть первой.
Вкладки дашборда: как задача попадает и что смотреть#
| Вкладка | Как задача туда попадает | На что смотреть |
|---|---|---|
| pending | Поставлена и ждёт свободного воркера | Рост списка без движения active — не хватает параллелизма |
| active | Хендлер исполняется сейчас | Строка, живущая часами, — кандидат на таймаут |
| scheduled | ProcessIn, Deadline или периодика | Длина — ваши обещания на будущее |
| retry | Попытка провалилась, пауза растёт | Одинаковый LastErr — внешний сервис |
| archived | Попытки кончились или SkipRetry | Досье для ручного разбора и запуска |
| completed | Успех с опцией Retention(d) | Пусто без Retention — это норма |
| aggregating | Ждёт сборки в группе | Копится — пачки перестали собираться |
Проверка: пустая вкладка completed
Система сутки обрабатывает задачи успешно, но вкладка completed в asynqmon пуста. Почему?
Метрики успешности и ошибок#
Состояния отвечают на вопрос «где задача», а графики — «как идёт работа». Asynqmon рисует по каждой очереди динамику обработок: сколько попыток исполнилось за день и сколько из них провалилось — те же числа, что возвращает DailyStats из пятнадцатого урока, только без скрипта под рукой. Первый график полезен пропускной способностью: провал processed после деплоя виден раньше тикетов, а сравнение с предыдущими сутками показывает, насколько именно просела очередь. Второй — по ошибкам: всплеск failed при ровном processed означает, что началось что-то новое, и причина ищется на вкладке retry по LastErr; доля ошибок — число, которое бизнес понимает без перевода. Помните честность счётчиков из пятнадцатого урока: processed включает и успешные, и упавшие попытки, поэтому долю ошибок считайте сами — failed делить на processed. Для стойких алертов графиков дашборда мало: их место — в системе мониторинга, куда числа уводит двадцать третий урок; asynqmon остаётся взглядом при разборе, а не источником SLA. И маленькая деталь: статистика считается по суткам, так что сравнение «вчерашний день против сегодняшнего» — штатный режим чтения этих графиков, а не экзотика. Если график расходится с ощущениями команды, верьте графику и разбирайте, откуда ощущение: чаще всего ждут, что очередь «догонит», а она честно исполняет ровно то, что поставлено.
Дашборд рядом с Redis в compose
GOservices:
redis:
image: redis:7-alpine
ports:
- "6379:6379"
asynqmon:
image: hibiken/asynqmon
ports:
- "8080:8080"
environment:
- REDIS_URL=redis://redis:6379Сервисы compose живут в одной сети, и дашборд добирается до Redis по имени сервиса: в REDIS_URL хост — redis, потому что внутри контейнера localhost — это сам asynqmon. Оба порта проброшены на хост: воркеры подключаются к localhost:6379, браузер открывает localhost:8080. Итог — все трое смотрят в одну базу.
Команда завела алерт «completed пуст — очередь сломалась» и две недели жила на ложных срабатываниях: без Retention вкладка пуста по умолчанию. Если успешные задачи нужно видеть — ставьте Retention(d) на постановку и закладывайте место в Redis под хранение; если важна доля успехов — считайте её из processed и failed, а не из длины вкладки. Пустой completed — норма, а не симптом: у задачи, чей успех важен для аудита, Retention появляется в той же строке постановки, что и MaxRetry.
Отладка лагов очереди#
Сценарий, ради которого asynq дашборд держат под рукой. Тикет: письма уходят с опозданием в час. Шаг первый — вкладка очереди: сравните processed с обычным днём; скорость просела — проблема производительности, а не маршрута. Шаг второй — pending: длинный список при живых active означает, что воркер не успевает, — вопрос к Concurrency или к тяжести задач. Шаг третий — retry: рост вкладки с одинаковым LastErr указывает на внешний сервис, разброс ошибок — на собственный код, а экспонента пауз уже знакома вам по шестому уроку; по LastFailedAt видно, когда всё началось. Шаг четвёртый — active: задача, висящая часами, — кандидат на таймаут из одиннадцатого урока. Шаг пятый — кнопки: Run перезапускает застрявшую после починки, Archive снимает неактуальную постановку. Каждая кнопка — та же операция, что RunTask и ArchiveTask из пятнадцатого урока: asynqmon пишет в те же ключи Redis, и задача честно переезжает между вкладками. Отличие одно — аудит: вызов из скрипта логирует ваш код, а кто нажал кнопку, история не скажет, поэтому ручные операции в проде идут через админку с логами, а дашборд остаётся инструментом первого взгляда и быстрых исправлений. Сам сценарий занимает минуты: от тикета до кнопки — пять вкладок, и каждая отсекает половину версий.
Где задача после успеха?
Прочитайте код и выберите, что он выведет:
// постановка:
client.Enqueue(task) // без asynq.Retention
// хендлер отработал, вернул nil, ретраев не было
// открываем asynqmon и ищем задачуБезопасность дашборда в проде#
Asynqmon — административный интерфейс: права у него те же, что у Inspector из кода. На машине разработчика он не требует ничего — и это нормально: локальный Redis ничего не решает. В проде к нему относятся как к панели управления базой: доступ по VPN или за аутентификацией reverse-proxy, отдельный порт, который не торчит наружу, и правило «не публиковать дашборд без защиты». Кнопки Run, Archive и Delete меняют данные очереди так же, как одноимённые методы Inspector, поэтому авторизация и логирование действий — не опция, а часть установки: кнопка без истории — это изменение данных без автора. Если по состоянию очереди строятся отчёты для людей без прав на вмешательство, честнее read-only путь: скрипт на Inspector с одними методами чтения или экспорт метрик в систему мониторинга — там графики и живут постоянно. Бывает и обратная ситуация: браузера нет, а очередь посмотреть надо — например, по SSH на сервере в полночь. Для этого у CLI-утилиты asynq есть команда asynq dash — терминальный дашборд, который читает те же ключи Redis. Данные, форма доступа, ответственность — три разные вещи, и asynqmon закрывает только первую из них.
Правила эксплуатации asynqmon#
- Дашборд смотрит в тот же Redis, что и воркеры: иной адрес — пустой интерфейс.
- Пустая вкладка completed — норма: успешные задачи живут там только с Retention.
- Кнопки Run, Archive, Delete — те же операции Inspector: логируйте, кто и что сделал.
- В проде asynqmon прячут за аутентификацией или VPN: это админ-панель очереди.
- Числа дашборда равны числам Inspector: расхождение — разное время среза, не баг.
- Флаги и переменные образа сверяйте с README asynqmon — проект живёт отдельно.
Проверка: откуда цифры дашборда
Почему счётчики очереди в asynqmon совпадают с GetQueueInfo из Inspector?
Соберите команду запуска
Допишите порт хоста и имя образа asynqmon.
Соберите compose для дашборда
Расставьте строки docker-compose: Redis, asynqmon, порт и адрес базы.
Строки
Ваша программа
Нажимайте на строки слева, чтобы собрать программу
Дашборд — сетевой инструмент: песочница сайта не поднимет ни Docker, ни Redis и покажет только интерактивы урока. Всё остальное — docker run, compose, вкладки в браузере — живёт в вашем терминале: одной команды и открытой вкладки достаточно.
Карточки: asynqmon
Asynqmon уложен в один рабочий жест: docker run на порту 8080, семь вкладок состояний, графики обработок и кнопки тех же операций, что Inspector из кода. Мини-эксперимент: поднимите Redis и дашборд рядом, поставьте задачу с ProcessIn(2time.Minute) и посмотрите, как она переезжает scheduled → pending → active и исчезает после успеха; затем добавьте Retention(10time.Minute) и найдите её на вкладке completed. Формат прежний: код запускается локально с Go и Redis в Docker, песочница сайта показывает тематическую программу на чистом Go. Дашборд не требует кода, но и не пишет его за вас: привычка сверять вкладки после каждого деплоя отлавливает половину проблем раньше тикетов. Дальше по курсу: семнадцатый урок вернётся к хендлерам — как передавать им контекст и зависимости, а числа дашборда позже вплетутся в логи и метрики двадцать третьего урока про наблюдаемость.
Песочница урока
Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.
Запустите код, чтобы увидеть вывод.
Коротко: что запомнить
- Asynqmon — отдельный репозиторий hibiken/asynqmon: веб-инструмент мониторинга и администрирования очередей asynq.
- Типовой запуск — docker run -p 8080:8080 hibiken/asynqmon; адрес Redis передаётся в REDIS_URL.
- Семь состояний — семь вкладок: active, pending, scheduled, retry, archived, completed, aggregating.
- Без Retention успешные задачи удаляются сразу: пустая вкладка completed — норма, а не симптом.
- Числа дашборда совпадают с Inspector: читаются одни и те же ключи Redis.
- Processed включает упавшие попытки: долю ошибок считайте сами — failed делить на processed.
- Кнопки Run, Archive, Delete — те же операции, что RunTask и ArchiveTask из пятнадцатого урока.
- В проде дашборд прячут за аутентификацией: это админ-панель очереди, а не витрина.
Домашнее задание
Поднимите Redis и asynqmon из compose урока и повторите путь задачи: поставьте с ProcessIn(2*time.Minute), проследите scheduled → pending → active, затем добавьте Retention(10*time.Minute) и найдите задачу на вкладке completed. Устройте затык: хендлер, который всегда падает, с MaxRetry(3) — и разберите вкладку retry по LastErr и NextProcessAt, сверяя экспоненту пауз. В финале остановите воркер на минуту и посмотрите, как ведёт себя pending при пустом active. Всё локально: Docker, Redis, браузер; песочница сайта сетевой код не исполняет.
Личные заметкиПусто
Вопросы и ответы по уроку
Asynqmon нужно подключать в код воркера?
Нет: это отдельное приложение, которому нужен только адрес Redis. В Go-программу добавлять нечего, клиент и сервер работают как раньше; дашборд лишь читает те же ключи, поэтому его можно поднять и остановить в любой момент без рестартов воркеров.
Можно ли давать asynqmon дежурным в проде?
Можно, но как административный интерфейс: кнопки запуска, архивации и удаления меняют данные очереди. Минимум гигиены — аутентификация перед дашбордом в reverse-proxy или доступ по VPN, плюс логирование ручных операций. Для отчётов без права вмешательства лучше read-only путь через Inspector или экспорт метрик.
Чем asynqmon отличается от утилиты asynq?
Asynqmon — веб-интерфейс в браузере с вкладками состояний и графиками. Утилита asynq — CLI: статистика, списки задач и терминальный дашборд asynq dash для случая без браузера. Оба читают тот же Redis, что и Inspector, поэтому числа совпадают во всех трёх формах.
Термины урока
Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.
Изучайте дальше
Следующая ступень учебного пути
Kafka в Go: продюсеры и консьюмеры на kafka-go
Курс Kafka для Go: топики и партиции, producer и consumer, группы, оффсеты, гарантии доставки, rebalance, Admin API и мониторинг. 25 уроков.
- Понимать топики, партиции, оффсеты и группы консьюмеров
- Писать продюсеры с ключами, батчами и ретраями
- Читать сообщения группой с коммитами оффсетов
- Выбирать гарантии: at-most-once, at-least-once