57 lines
5.7 KiB
Markdown
57 lines
5.7 KiB
Markdown
## MODIFIED Requirements
|
||
|
||
### Requirement: Цикл выполнения
|
||
Агент SHALL работать одним процессом: `claim` к хабу (долгий запрос) → при получении команды: досыпать до
|
||
`pause_seconds` от последнего вызова Jira → запись «started» в журнал → выполнение по контракту `commands` → запись
|
||
«finished» с результатом → отчёт хабу, повторяемый до подтверждения. Одна команда в полёте: новый `claim` агент SHALL
|
||
отправлять, только когда у него нет выданной, но не завершённой и не отчитанной команды (на этом хаб строит повторную
|
||
выдачу, см. `commands`). При изменении `settings_version` в ответе `claim` агент SHALL перечитать настройки до выполнения
|
||
команды.
|
||
|
||
#### Scenario: Остановка между командами
|
||
- **WHEN** получен Ctrl-C во время выполнения команды
|
||
- **THEN** текущая команда доделывается и отчёт отправляется, затем процесс завершается
|
||
|
||
### Requirement: Журнал на диске и восстановление
|
||
Агент SHALL вести `journal.jsonl` (только дозапись) рядом с собой: строки `claimed {command_id, at}` (сразу после
|
||
получения команды, до паузы), `started {command_id, at}`, `finished {command_id, status, result, error, jira_calls,
|
||
rate_limited, at}`, `acked {command_id, at}`. При старте агент SHALL: отправить хабу все `finished` без `acked`; для
|
||
`claimed`/`started` без `finished` — запросить команду у хаба по id и, если она в хабе всё ещё `claimed`, выполнить её
|
||
заново по правилу «проверь, потом сделай» с паузой `pause_seconds` из ответа хаба, не записывая `claimed` повторно.
|
||
Команда `python3 agent.py prune` SHALL удалять из журнала записи с `acked` старше 30 дней.
|
||
|
||
#### Scenario: Падение после ответа Jira
|
||
- **WHEN** агент упал между `POST /issue` и записью `finished`, затем перезапущен
|
||
- **THEN** агент находит в журнале `started` без `finished`, запрашивает команду у хаба, находит созданную задачу поиском
|
||
дубля и отчитывается `done` с её ключом; второй задачи нет
|
||
|
||
#### Scenario: Восстановление без лишней записи
|
||
- **WHEN** в журнале `claimed 40` без `finished`, хаб отдаёт команду 40 в `claimed` с `pause_seconds = 30`
|
||
- **THEN** в журнал дописываются `started 40`, `finished 40`, `acked 40`; второй строки `claimed 40` нет; перед выполнением
|
||
агент выдерживает 30 с от последнего вызова Jira
|
||
|
||
### Requirement: Ограничение темпа и 429
|
||
Агент SHALL помнить время последнего вызова Jira (любого) и не начинать команду раньше `pause_seconds` после него. При
|
||
старте агент SHALL принять за время последнего вызова Jira самое позднее `at` в журнале (если оно не в будущем); при пустом
|
||
журнале паузы перед первой командой нет. На HTTP 429 и 503 агент SHALL ждать `Retry-After` (иначе 60 с × номер попытки)
|
||
и повторять тот же запрос до 5 раз, считая попытки в `rate_limited`; после 5 неудач — `failed`. Пауза между записями
|
||
внутри одной команды — по зазору типа команды.
|
||
|
||
#### Scenario: 429 с Retry-After
|
||
- **WHEN** Jira ответила 429 с `Retry-After: 90`
|
||
- **THEN** агент ждёт 90 с, повторяет тот же запрос; в отчёте `rate_limited = 1`
|
||
|
||
#### Scenario: Перезапуск не сбивает темп
|
||
- **WHEN** последняя запись журнала `finished` сделана 10 с назад, агент перезапущен и получил команду с `pause_seconds = 30`
|
||
- **THEN** агент ждёт около 20 с перед первым вызовом Jira по команде
|
||
|
||
### Requirement: Доставка и запуск
|
||
README агента SHALL описывать: копирование `agent.py` и `agent.example.json` через общую папку, заполнение `agent.json`
|
||
(включая выбор транспорта в `hub_url`), `check`, запуск в терминале и через `nohup` с логом, опциональный launchd-plist,
|
||
`prune`. Версия агента SHALL быть в константе файла (3 — с восстановлением темпа после перезапуска) и в каждом отчёте;
|
||
хаб предупреждает в `agent_status`, если версия ниже минимальной из настроек.
|
||
|
||
#### Scenario: Устаревший агент
|
||
- **WHEN** агент версии 1 выходит на связь, а в настройках `min_agent_version = 2`
|
||
- **THEN** `agent_status.warning` = «обновите агента», команды выдаются по-прежнему
|