Инструкция агенту, который пишет скрипты для z3nDash

Ты пишешь скрипт, запускаемый планировщиком z3nDash. Используй встроенный API для управления расписанием своей задачи. Реализуй бизнес-логику пользователя и добавляй отсрочку только для тех ситуаций, где она требуется.

Контекст запуска

  • Адрес API общий для приложения. Каждый запуск автоматически получает свой контекст.
  • Не ищи задачу по имени, пути скрипта или списку задач. Один файл может запускаться несколькими задачами одновременно. Не читай и не редактируй БД планировщика.
  • Не проси пользователя вручную задавать ID, токен или порт. Не прописывай их в коде.
  • Во внешних процессах доступны переменные окружения Z3NDASH_API_URL, Z3NDASH_RUN_TOKEN, Z3NDASH_TASK_ID, Z3NDASH_RUN_ID.
  • Для управления собой используй /api/v1/self: ID в запросе не нужен.
  • Токен относится к одному запуску и перестаёт действовать после его завершения. Не сохраняй его для следующих запусков и не выводи в логи.
  • Вне запуска через z3nDash контекст отсутствует. Сообщи об этом явно; не подставляй выдуманные значения и не заявляй, что управление расписанием сработало.

Семантика управления

  • defer запрещает новые автоматические запуски всей текущей задачи до указанного времени, включая очередь. Другие задачи и уже работающие экземпляры продолжаются.
  • defer сам по себе не завершает и не останавливает текущий скрипт. Дождись ответа, освободи ресурсы и заверши работу обычным способом, сохранив статус ошибки при ошибке.
  • Не заменяй отсрочку часовым sleep: он удерживает работающий экземпляр.
  • Отсрочка переживает перезапуск приложения. Обычное расписание сохраняется.
  • Повторная отсрочка может продлить паузу, но не сократить уже установленную. Используй возвращённый deferred_until, если нужно вывести фактический срок.
  • После истечения отсрочки запускается обычный механизм расписания: запуск ровно в указанную секунду не гарантируется, период проверки — одна минута.
  • pause приостанавливает автоматические запуски бессрочно.
  • resume снимает и бессрочную паузу, и временную отсрочку. Не вызывай его автоматически при старте скрипта или в finally: так можно снять паузу, установленную другой нитью.
  • resume не меняет enabled и режим расписания. Ручной Run может обойти отсрочку; скрипт не должен вызывать его для обхода своей паузы.

Python

Используй поставляемый с приложением модуль. z3nDash добавляет его в PYTHONPATH, включая venv. Не устанавливай одноимённый пакет из PyPI и не создавай свой z3ndash.py.

from z3ndash import current_task

state = current_task.get()
state = current_task.defer(seconds=3600, reason="Сервис временно недоступен")

Также доступны current_task.pause(), current_task.resume() и current_task.defer(until=aware_datetime_or_iso_string, reason="..."). Передавай ровно одно из seconds или until.

При интеграции обработчика ошибок используй такую структуру. perform_work и TemporaryServiceError здесь обозначают реальную функцию и временную ошибку конкретного скрипта: замени их подходящими именами, не оставляй заглушки.

import logging
from z3ndash import current_task

try:
    perform_work()
except TemporaryServiceError:
    try:
        state = current_task.defer(seconds=3600, reason="Сервис временно недоступен")
        logging.warning("Следующие запуски отложены до %s", state["deferred_until"])
    except Exception:
        logging.exception("Не удалось подтвердить отсрочку в z3nDash")
    raise  # Сохранить исходную ошибку и не сообщать об успешном выполнении.

Не превращай все исключения в временные: ошибки кода, отмена и ожидаемое отсутствие данных должны обрабатываться согласно требованиям конкретного скрипта.

C# / CSX / XML OwnCode

В csx-internal и XML OwnCode, исполняемых именно z3nDash, объект current_task предоставляется средой. Не создавай его самостоятельно.

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

Остальные методы: GetAsync(), PauseAsync(), ResumeAsync(), DeferUntilAsync(DateTimeOffset until, string reason = ""). Для синхронного блока: current_task.DeferAsync(3600).GetAwaiter().GetResult();. Дождись завершения вызова, затем заверши скрипт; не оставляй запрос фоновой задачей. При обработке ошибки не маскируй исходное исключение ошибкой вызова API. Внутри встроенных обработчиков приложения доступен TaskRunContext.Current. Для отдельного C#-процесса используй HTTP и переменные окружения, как для других языков.

HTTP для Node.js, PowerShell и других языков

Базовый адрес: значение Z3NDASH_API_URL без завершающего /. Заголовок каждого запроса: Authorization: Bearer <значение Z3NDASH_RUN_TOKEN>. POST передаёт JSON с Content-Type: application/json.

Метод Путь Тело
GET /api/v1/self Нет
POST /api/v1/self/defer {"delay_seconds":3600,"reason":"Сервис недоступен"}
POST /api/v1/self/defer {"until":"2030-01-01T12:00:00Z","reason":"До указанного времени"}
POST /api/v1/self/pause {}
POST /api/v1/self/resume {}

В примере until дата иллюстративная: вычисляй требуемую будущую дату из условий задачи. Обязательно указывай Z или смещение UTC. delay_seconds — положительное конечное число секунд от момента запроса. Не передавай одновременно оба поля. Причина необязательна, до 2000 символов; не включай в неё секреты.

Ответ всех команд — JSON-объект с полями task_id, run_id, name, enabled, paused, deferred_until, reason, schedule_mode. deferred_until может быть null. В Python это словарь; в C# — объект со свойствами TaskId, RunId, Name, Enabled, Paused, DeferredUntil, Reason, ScheduleMode.

Проверяй HTTP-статус до обработки успешного ответа. Ошибка имеет тело {"error":"..."}. 400 означает неверные параметры, 401 — отсутствующий или истёкший токен, 404 — отсутствующую задачу/команду, 503 — неподключённую БД, 500 — внутреннюю ошибку. Не повторяй 400/401 бесконечно. При таймауте результат неизвестен: не утверждай, что пауза установлена; при необходимости проверь состояние через GET /self. Используй конечный сетевой таймаут. Локальный API не должен идти через рабочий прокси скрипта. Встроенные помощники Python и C# уже обходят прокси и имеют таймаут 15 секунд.

Что проверить перед сдачей скрипта

  • Нет вручную заданного адреса, порта, ID или поиска себя среди задач.
  • Отсрочка вызывается в нужной ветке ошибки и ожидается до завершения скрипта.
  • При неудаче запроса нет ложного сообщения об установленной паузе.
  • Нет автоматического resume, долгого ожидания вместо отсрочки или остановки чужих нитей.
  • Ресурсы освобождаются, исходная ошибка не теряется, токен не попадает в вывод.
  • Укажи, проверялся ли скрипт реальным запуском через z3nDash. Обычный запуск из терминала без контекста не подтверждает работу интеграции.

Справочник API приложения: Task API. Не добавляй неподтверждённые методы SDK или эндпоинты. Для действий вне текущей задачи сначала уточни требуемый объём управления.