feat(hands,jobs): drill days skip the beat and ack carries the alert decision
This commit is contained in:
1 parent
47c31ac356
commit
a39e0b27af
4 files changed
+135
-7
No files matched your search
@@ -54,6 +54,7 @@ __all__ = [
|
||||
"ack_line",
|
||||
"alarm_text",
|
||||
"beat_line",
|
||||
"drill",
|
||||
"every_from_cron",
|
||||
"look",
|
||||
"parse_beat",
|
||||
@@ -208,12 +209,21 @@ def ack_line(
|
||||
threshold: timedelta | None,
|
||||
fallback: bool,
|
||||
full: bool,
|
||||
alert: Literal["fired", "held", "none"],
|
||||
) -> str:
|
||||
"""Расписка о прогоне в комнату: что видели, чем мерили и вооружены ли.
|
||||
"""Расписка о прогоне в комнату: что видели, чем мерили и что решили.
|
||||
|
||||
`win=` - про само окно: `25` это «последние 25 сообщений комнаты прочитаны
|
||||
целиком», `25/partial` - «дочитать историю не удалось», `stale` - «окно
|
||||
смотрит в прошлое». Пустое окно при `partial` ничего не доказывает.
|
||||
|
||||
`alert=` - РЕШЕНИЕ ПРИБОРА в этом прогоне, а не факт того, что человек
|
||||
сосед что-то получил: `fired` - тревога (`silence` или `unarmed`) в этом
|
||||
прогоне взята и отдана дальше, `held` - порог пройден, но тревога
|
||||
подавлена как повтор (предыдущая уходила меньше `REPEAT` назад), `none` -
|
||||
тревоги нет. Доставка решается за пределами сторожа - мастером и
|
||||
диспетчером, - и её отказ виден в логе, а не тут: без арифметики соседу
|
||||
видно было только, что мы что-то посчитали, но не что мы из этого поняли.
|
||||
"""
|
||||
mark = span(threshold) + ("-fallback" if fallback and threshold else "")
|
||||
read = "stale" if stale else f"{window}" if full else f"{window}/partial"
|
||||
@@ -221,10 +231,26 @@ def ack_line(
|
||||
f"ack {peer} last={_iso(last) or ('never' if not armed else 'unknown')} "
|
||||
f"seen={_iso(seen) or 'never'} res={span(res)} "
|
||||
f"win={read} armed={'yes' if armed else 'no'} "
|
||||
f"thr={mark}"
|
||||
f"thr={mark} alert={alert}"
|
||||
)
|
||||
|
||||
|
||||
def drill(path: Path, *, now: datetime, tz: tzinfo) -> bool:
|
||||
"""Стоит ли сегодняшняя дата в файле флага учений.
|
||||
|
||||
Файл - список дат `YYYY-MM-DD`, по одной на строку; дата - локальная дата
|
||||
прогона в зоне планировщика, той же, в которой читаются кроны. Файла нет,
|
||||
он пуст или нечитаем - учений нет, и отметка уходит как обычно: флаг
|
||||
выключает прибор, поэтому его отсутствие должно значить «работаем».
|
||||
"""
|
||||
try:
|
||||
raw = path.read_text(encoding="utf-8")
|
||||
except OSError:
|
||||
return False
|
||||
today = now.astimezone(tz).strftime("%Y-%m-%d")
|
||||
return today in {line.strip() for line in raw.splitlines()}
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class Watch:
|
||||
"""Состояние между прогонами: файл на диске, переживает передеплой."""
|
||||
@@ -356,6 +382,7 @@ def look(
|
||||
state.unarmed_since = now
|
||||
|
||||
alarm: Literal["silence", "unarmed"] | None = None
|
||||
held = False
|
||||
if stale:
|
||||
pass
|
||||
elif not full:
|
||||
@@ -376,6 +403,7 @@ def look(
|
||||
if state.alerted is None or now - state.alerted >= REPEAT:
|
||||
alarm = "silence"
|
||||
else:
|
||||
held = True
|
||||
note += "; тревога уже уходила меньше суток назад"
|
||||
|
||||
return Report(
|
||||
@@ -390,6 +418,7 @@ def look(
|
||||
threshold=threshold,
|
||||
fallback=state.every_unknown,
|
||||
full=full,
|
||||
alert="fired" if alarm is not None else "held" if held else "none",
|
||||
),
|
||||
stale=stale,
|
||||
full=full,
|
||||
|
||||
Reference in new issue
Block a user