Внешние воркеры

По умолчанию CronBox выполняет запросы со своих серверов. Внешний воркер - это ваш процесс на вашей инфраструктуре: он забирает назначенные ему задачи из CronBox, выполняет HTTP-запрос из вашей сети и отправляет результат обратно.

Когда это нужно

  • Целевой сервис доступен только из закрытого контура, VPN или локальной сети - из интернета до него не достучаться.
  • Принимающая сторона пускает запросы только с определённых IP, и вы хотите использовать свои адреса, а не наши.
  • Нужно, чтобы сетевое соединение с целевым сервисом устанавливалось из вашего периметра.

Что всё равно хранится в CronBox: описание задачи (URL, заголовки, тело) и результат, который присылает воркер - код ответа, тело ответа, длительность и текст ошибки. Внешний воркер меняет только то, откуда уходит сетевой запрос.

Как это работает

  1. 1

    Зарегистрируйте воркера

    В ответе один раз показывается ключ вида wk_... - сохраните его, повторно он не выдаётся.

  2. 2

    Запустите процесс у себя

    Он аутентифицируется заголовком X-Worker-Key и работает по протоколу ниже.

  3. 3

    Назначьте задачу воркеру

    Передайте worker_id при создании или обновлении cron-задачи либо отложенной задачи. Без worker_id задачу выполнят наши воркеры.

Протокол воркера

  • Heartbeat - раз в 30 секунд. Если heartbeat не приходит больше 60 секунд, воркер помечается как offline.
  • Опрос задач - короткий polling: сервер отвечает сразу и возвращает поле poll_interval_seconds (по умолчанию 5).
  • Отправка результата - после выполнения запроса.

Эндпоинты

Управление воркерами - Bearer-токен владельца рабочего пространства:

GET
/workspaces/{workspace_id}/workers

Список воркеров рабочего пространства

POST
/workspaces/{workspace_id}/workers

Регистрация воркера, ключ возвращается один раз

PATCH
/workspaces/{workspace_id}/workers/{id}

Переименование, включение и отключение

DELETE
/workspaces/{workspace_id}/workers/{id}

Удаление воркера

POST
/workspaces/{workspace_id}/workers/{id}/regenerate-key

Перевыпуск ключа, старый отзывается сразу

Эндпоинты самого воркера - заголовок X-Worker-Key:

GET
/worker/info

Информация о текущем воркере

POST
/worker/heartbeat

Подтверждение, что воркер жив

GET
/worker/tasks

Получение задач, max_tasks от 1 до 100

POST
/worker/tasks/result

Отправка результата выполнения

Регистрация воркера

curl -X POST https://api.cronbox.ru/v1/workspaces/WORKSPACE_ID/workers \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "prod-dmz-01",
    "description": "Воркер во внутренней сети"
  }'
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "prod-dmz-01",
  "api_key": "wk_...",
  "api_key_prefix": "wk_abcdefg"
}

Назначение задачи воркеру

curl -X POST https://api.cronbox.ru/v1/workspaces/WORKSPACE_ID/cron \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Синхронизация с 1С",
    "url": "http://10.0.0.15:8080/sync",
    "method": "POST",
    "cron_expression": "0 */6 * * *",
    "worker_id": "550e8400-e29b-41d4-a716-446655440000"
  }'

Минимальный клиент

Полноценный клиент - это цикл из трёх вызовов. Пример на Python с httpx:

import os, time
from datetime import datetime, timezone
import httpx

API = os.environ["CRONBOX_API_URL"]     # https://api.cronbox.ru/v1
KEY = os.environ["CRONBOX_WORKER_KEY"]  # wk_...
api = httpx.Client(headers={"X-Worker-Key": KEY}, timeout=30)

while True:
    api.post(f"{API}/worker/heartbeat", json={"status": "online", "current_tasks": 0})
    tasks = api.get(f"{API}/worker/tasks", params={"max_tasks": 10}).json()["tasks"]

    for task in tasks:
        started = datetime.now(timezone.utc)
        try:
            resp = httpx.request(
                task["method"], task["url"],
                headers=task["headers"], content=task["body"],
                timeout=task["timeout_seconds"],
            )
            outcome = {"status_code": resp.status_code, "response_body": resp.text[:10000]}
        except Exception as exc:
            outcome = {"error": str(exc), "error_type": "connection_error"}
        finished = datetime.now(timezone.utc)

        api.post(f"{API}/worker/tasks/result", json={
            "task_id": task["task_id"],
            "task_type": task["task_type"],
            "started_at": started.isoformat(),
            "finished_at": finished.isoformat(),
            "duration_ms": int((finished - started).total_seconds() * 1000),
            **outcome,
        })

    time.sleep(5)

Ограничения

  • Внешние воркеры выполняют только HTTP-задачи двух типов: cron и отложенные. ICMP- и TCP-проверки, цепочки задач и мониторы всегда выполняются на наших воркерах.
  • Отдельного раздела для воркеров в панели управления пока нет - они создаются, переименовываются и удаляются через API.
  • Выданная задача не переотправляется: если воркер забрал задачу и не прислал результат, повторной выдачи не будет.
  • Задача ждёт воркера в его очереди 24 часа, после чего удаляется.

Наши IP-адреса для allowlist

Если внешний воркер не нужен, но целевой сервис закрыт списком разрешённых адресов, добавьте в него адрес, с которого CronBox отправляет запросы и проверки:

45.133.150.194

С этого же адреса приходят ICMP- и TCP-проверки и проверки SSL-сертификатов. IPv6 сейчас не используется. Адрес может измениться при переезде инфраструктуры - актуальный список всегда на этой странице.