Управление задачей из скрипта

Программа выдаёт каждому запуску собственный контекст. Адрес API общий; ID задачи и запуска определяются автоматически. Один файл можно использовать в нескольких задачах. Искать задачу по имени или читать ID из БД не нужно.

Python

Модуль z3ndash поставляется с приложением. Планировщик автоматически добавляет его в PYTHONPATH, включая запуски в venv. Устанавливать пакет через pip не нужно.

from z3ndash import current_task

try:
    do_work()
except ServiceUnavailable:
    current_task.defer(seconds=3600, reason="Сервис недоступен")
    raise

defer() не завершает скрипт и не подавляет ошибки. После подтверждения отсрочки скрипт сам решает, закончить работу, освободить ресурсы или выбросить исключение. Если API недоступен, помощник выбрасывает исключение: отсрочку нельзя считать установленной.

state = current_task.get()       # task_id, run_id, name и состояние расписания
current_task.pause()             # Приостановить автоматические запуски без срока
current_task.resume()            # Снять паузу и временную отсрочку
current_task.defer(until="2026-12-01T12:00:00Z", reason="До указанного времени")

C# и XML OwnCode

В csx-internal и блоках XML OwnCode доступен объект current_task:

await current_task.DeferAsync(3600, "Сервис недоступен");
var state = await current_task.GetAsync();

В синхронном блоке: current_task.DeferAsync(3600).GetAwaiter().GetResult();. Во внутренних обработчиках программы тот же контекст доступен как TaskRunContext.Current. Контекст изолирован между параллельными запусками.

HTTP API

Внешние процессы получают Z3NDASH_API_URL, Z3NDASH_RUN_TOKEN, Z3NDASH_TASK_ID, Z3NDASH_RUN_ID через окружение. Адрес содержит фактический порт работающего приложения. Для /self достаточно адреса и токена. Каждый запрос передаёт заголовок Authorization: Bearer <Z3NDASH_RUN_TOKEN>. Токен действует только до завершения запуска. Не выводите его в логи.

Метод Путь Тело
GET /api/v1/self —
POST /api/v1/self/defer {"delay_seconds":3600,"reason":"Ошибка сервиса"}
POST /api/v1/self/defer {"until":"2026-12-01T12:00:00Z"}
POST /api/v1/self/pause {}
POST /api/v1/self/resume {}

Ответ всех команд — состояние: task_id, run_id, name, enabled, paused, deferred_until (UTC или null), reason, schedule_mode. Токен в ответ не входит. delay_seconds — положительное число секунд от момента запроса. until — будущее время с Z или смещением UTC. Нельзя передавать оба поля одновременно. Причина необязательна, максимум 2000 символов. Ошибки: 400 — неверные параметры, 401 — отсутствующий/завершённый контекст, 404 — задача/команда не найдена, 503 — БД не подключена, 500 — внутренняя ошибка. Тело ошибки: {"error":"..."}.

Пример для Node.js:

const response = await fetch(process.env.Z3NDASH_API_URL + '/api/v1/self/defer', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json',
             Authorization: 'Bearer ' + process.env.Z3NDASH_RUN_TOKEN },
  body: JSON.stringify({ delay_seconds: 3600, reason: 'Сервис недоступен' })
});
if (!response.ok) throw new Error(await response.text());

Поведение расписания

  • Отсрочка относится ко всей задаче. Уже допущенные к выполнению экземпляры продолжаются; новые автоматические запуски и очередь ждут.
  • Зарезервированные экземпляры, ожидающие стартовой задержки, тоже проверяют паузу.
  • Отсрочка и бессрочная пауза сохраняются в БД и переживают перезапуск приложения.
  • Конкурирующие отсрочки выбирают самое позднее время. Сократить его можно только явным resume, затем новым defer.
  • По истечении отсрочки действует прежнее расписание и его ограничения. Это запрет запускать раньше указанного времени, а не обещание запуска точно в эту секунду. Планировщик проверяет готовность раз в минуту.
  • Ручной Run запускает задачу сразу и не снимает отсрочку. Ручной запуск, попавший в очередь из-за занятых нитей, ждёт вместе с очередью.
  • resume снимает паузу/отсрочку, но не меняет enabled и режим расписания. Отключённую задачу нужно отдельно включить.
  • В Tasker видны срок отсрочки и кнопка Resume schedule для её снятия.

Управление программой извне

Существующий API браузерного интерфейса продолжает работать на том же адресе: GET /tasker/list, POST /tasker/save, /tasker/run, /tasker/stop, /tasker/delete, GET /tasker/instances?id=..., /tasker/queue?id=.... Для команд run/stop/delete передаётся JSON {"id":"ID задачи"}. save принимает id и изменяемые поля задачи, например enabled, schedule_mode, cron, schedule_json. Без id создаёт новую задачу.

Добавлены команды оператора: POST /tasker/pause и /tasker/resume с телом {"id":"..."}, а также POST /tasker/defer?id=... с тем же телом, что у /self/defer. Они используют существующий доступ к API панели. Для управления собственной задачей из скрипта используйте /self: ID там не нужен.