Исходящий webhook Asana
Считайте webhook частью инфраструктуры, а не закладкой разработчика: один стабильный POST на хост шлюза переживёт обновления Xcode, вывод узлов из пула и масштабирование сборщиков.
- Ресурс. В приложении Asana для автоматизации создайте webhook на проект, команду или портфель, который отражает готовность к сборке. URL вида
https://gateway.example/openclaw/v1/asana/webhookдержите выделенным и задокументированным (путь иллюстративный). - Handshake. На первом
POSTAsana пришлёт заголовокX-Hook-Secret: верните его же в ответных заголовках без изменений, ответьте200или204, затем сохраните значение как ключ для всех последующих проверокX-Hook-Signature(и сверьте тело ответа201, если используете REST-путь создания webhook). - Хранение секрета. Файл с правами вроде
0440и отдельный системный пользователь — по чеклисту секреты и минимальные права на узлах MeshMac. Секрет не кладите в образ сборщика: только на шлюз. - Фильтр на краю. В конфигурации отбрасывайте шумные типы событий: в очередь кладите переход в колонку «к сборке» или изменение согласованного пользовательского поля. Отклонённые по смыслу события всё равно должны быстро получать
200после аутентификации.
Ограничьте размер тела и число одновременных доставок согласно CPU шлюза, чтобы всплеск активности в Asana не «задавил» остальные SaaS-коллбеки.
Проверка подписи
Сначала подпись, потом JSON. Значение X-Hook-Signature — это шестнадцатеричный HMAC-SHA256 от точных байтов тела. Если middleware сначала парсит JSON, нормализует Unicode или «красиво» пересобирает тело, подпись начнёт расходиться под нагрузкой.
- Прочитайте сырое тело в буфер процесса шлюза до любого декодера JSON.
- Вычислите
HMAC_SHA256(сохранённый_секрет, raw_body), закодируйте в hex и сравните с заголовком в постоянном времени (пульсы Asana могут приходить с пустым JSON). - При несовпадении —
401и строка лога без секрета и полного payload (достаточно идентификатора доставки, маршрута и длины в байтах). - После успеха распарсьте конверт, дедуплицируйте по идентификатору доставки или короткому окну по хешу
resource.gid + action + время, затем ставьте в очередь.
200 отдавайте только после долговременной записи в очередь, иначе повторы Asana размножат джобы; это напрямую стыкуется с политикой идемпотентности в материале про очередь и повторы.
Маршрутизация на шлюзе OpenClaw
Маршрут — контракт между «что сказала Asana» и «что имеет право выполнить любой узел MeshMac». Держите таблицу скучной: пара (resource_type, action) в конфиге OpenClaw отображается в нормализованную задачу, которую уже понимают ваши скрипты сборки.
- Извлеките стабильные поля:
task_gid, gid проекта и секции, постоянную ссылку, пользовательские поля с репозиторием и веткой. - Соберите
idempotency_keyиз метаданных доставки (напримерwh_asana_{delivery_id}) или детерминированного хеша, если в вашем пути нет явного id. - Положите в общую очередь поля, ожидаемые билд-скриптом:
repo,ref,correlation_id. Опциональноpreferred_mesh_node_idдля GPU-лейнов — но избегайте жёсткой привязки к одному железу, если флот меняется. - Сгенерируйте внутреннее событие «сборка поставлена в очередь», чтобы дашборд показывал глубину до того, как Mac заберёт задачу.
Лимиты одновременных входящих webhook и сессий шлюза закладывайте заранее по вашему SLA, чтобы пики Asana не уперлись в исчерпание воркеров до приёма тела.
Шаблон уведомлений для нескольких узлов
Именно на этапе broadcast пулы Mac «расползаются»: каждый узел хочет «помочь» и самостоятельно дернуть Slack, Teams или Google Chat. Зафиксируйте один исходящий шаблон на шлюзе: одинаковые поля упрощают дедупликацию и чтение дежурным.
Минимальный набор полей JSON (или универсального webhook), который воркер передаёт шлюзу для трансляции:
build_idиidempotency_keytask_gidи человекочитаемый заголовок задачиmesh_node_id, hostname, версия Xcode или тулчейнаstatusиз набора{queued,running,succeeded,failed,canceled}duration_ms,exit_code, усечённыйlog_tail(например до 2 КБ)
При failed шлюз (не каждый Mac) собирает сводку для Asana: первая строка — исход, вторая — гипотеза (тесты, подпись, диск), ссылка на полные логи во внутреннем хранилище. Полные логи остаются в объектном хранилище или в вашей observability-стеке; в Asana — только исполнительное резюме, чтобы PM не запрашивал SSH.
Тот же дисциплинарный подход «один вход — много узлов» переносится и на другие SaaS: меняется транспорт, не меняется роль шлюза и нормализованные поля статуса.
FAQ: 401 и 429
- 401 на URL, который вызывает Asana
- Локально отклонена подпись: неверный файл секрета, тело изменено до HMAC или обратный прокси перекодировал gzip. Воспроизведите на стенде с тем же edge, сравните длину байтов входа в HMAC с фактическим телом и убедитесь, что секрет handshake совпадает с тем, что хранится для проверки.
- 401 только при записи комментария (story) в Asana
- Это уже исходящий PAT или OAuth, не webhook. На
401не накручивайте бесконечные повторы: проверьте область токена, workspace задачи, право создавать истории и что шлюз перечитал обновлённый файл ключа без устаревшего дескриптора. - 429 от REST Asana
- Превышены лимиты платформы или шлюз слишком болтлив. Сериализуйте обновления комментариев по одной задаче, применяйте экспоненциальный backoff с джиттером, уважайте
Retry-After, схлопывайте дубликаты сводок об одной и той же сборке в коротком окне дедупликации. - 429 от Slack, Teams или Google Chat
- Параллельные узлы при массовых падениях устраивают «штурм» чат-webhook. Централизуйте исходящие POST на шлюзе, ограничьте число одновременных клиентов, дедуплицируйте по
build_idи исходу, чтобы каждый Mac не открывал отдельный шланг. - Дубликаты при быстром перетаскивании задачи между колонками
- Ужесточите таблицу маршрутизации: требуйте стабильное пользовательское поле «готово к сборке» или debounce переходов секций. Включайте в ключ идемпотентности корзину по времени (например пять минут) вместе с gid задачи и целевой секцией.
Кратко
Итог: один шлюз OpenClaw, handshake Asana, проверка X-Hook-Signature по сырым байтам, общая очередь, единый шаблон broadcast, краткая сводка в задачу при ошибке и дисциплинированная работа с 401/429.
Публичные страницы без входа
Главная, индекс блога, справочный центр и тарифы и покупка доступны без регистрации — удобно заранее оценить, сколько узлов MeshMac нужно под шлюз и очередь.
Масштабируйте Mac — не умножайте webhook Asana
Дополнительные узлы MeshMac дают параллельные сборки без перевыпуска секретов Asana: ключ остаётся на шлюзе, очередь честно раздаёт задачи между Mac. Перед заказом откройте страницу тарифов и покупки (без входа в аккаунт), загляните в центр помощи по доступу, на главную и в индекс блога — спланируйте пропускную способность шлюза и число сборщиков, затем оформите покупку, когда контур Asana → OpenClaw → MeshMac будет готов к продакшену.