58 / SCHEDULER / PRODUCTION FABRIC
58 / PRODUCTION / TIME SIGNALS · RECURRENCE · DELAYS · DEADLINES

SCHEDULER.

Scheduler — production-компонент, который превращает правила времени в надёжные сигналы: «запусти один раз в 15:00», «каждый час», «через 20 минут», «по будням», «после задержки», «к дедлайну».

Главный принцип: scheduler не должен сам выполнять тяжёлую бизнес-работу. Его задача — вычислить, когда должно наступить действие, создать durable occurrence/job/event и передать выполнение queue/worker, workflow или trigger layer.
00. ARCHITECTURAL STATUS

НЕ КАЖДОЙ СИСТЕМЕ НУЖЕН ОТДЕЛЬНЫЙ SCHEDULER

Если у вас один локальный cron, который раз в день запускает sync, cron уже выполняет роль scheduler-а. Отдельный компонент появляется, когда расписаний много, они пользовательские, изменяемые, tenant-scoped, требуют retries/misfire semantics, DST/timezone correctness или должны переживать рестарты.
TYPEPRODUCTIONTime-based control infrastructure.
DEFAULTCONDITIONALТолько если time-triggered work реально есть.
ENABLE WHENTIME MATTERSRecurring tasks, delays, deadlines, reminders.
SEPARATE COMPONENTYESLogical responsibility, not necessarily separate server.
LIVES INPRODUCTION FABRICSupporting infrastructure.
COMPLEXITYLOW → HIGHCron → DB scheduler → distributed timers.
IMPLEMENT: WHEN TIME IS A DOMAIN
Минимум 80% ценности: durable schedule registry, one-time + recurring rules, timezone-aware next_run calculation, atomic occurrence creation, misfire policy, idempotency key per occurrence, pause/resume/update, audit/versioning, handoff to queue/workflow и lag metrics. Не нужен LLM scheduler: time computation and emission должны быть deterministic.
01A. ARCHITECTURE BOUNDARIES & OPERATIONS

EXPLICIT SYSTEM CONTRACT

A. BOUNDARY WITH NEIGHBORS

№42 Events & Triggers определяет смысл события и реакцию; scheduler создаёт time-originated event/occurrence. №57 Queues & Workers хранит и исполняет созданную работу; scheduler не владеет execution concurrency. №59 Broker / Message Bus транспортирует сообщения; scheduler может publish через broker, но не владеет pub-sub topology. №63 Retry/Circuit Breakers владеет общей resilience policy; scheduler отвечает только за delivery/misfire semantics time occurrence. №68 Durable Workflow владеет workflow timers внутри многошагового процесса; №58 — общий scheduler независимых scheduled jobs. №64 Budgets может ограничить количество/стоимость запланированных задач.

B. PREREQUISITES / CROSS-REFERENCES

Prerequisites: №10 State, №42 Events, №46 Observability, №50 Contracts, №57 Queues & Workers. Forward references: №59 Broker, №63 Retry/Circuit Breakers, №64 Budgets, №68 Durable Workflow, №69 Distributed Reliability.

C. PLANE PLACEMENT

REQUEST-TIME: create/update/cancel schedule may happen synchronously. CONTROL PLANE: schedule definitions, timezone, cadence, owner, status, next_run, misfire policy. DATA PLANE: emitted occurrences/jobs/events. OFFLINE: cleanup, reconciliation, calendar-rule tests, load/failure tests.

D. FAILURE & OPERATIONS CONTRACT

Success: each intended schedule occurrence becomes exactly one logical occurrence within allowed lateness. Retryable: transient DB/queue/broker outage before durable handoff. Permanent: invalid recurrence/timezone/expired schedule/forbidden owner. Idempotency: occurrence key = schedule_id + scheduled_for. Persist: rule/version/timezone/next_run/last_run/status/misfire policy/occurrence ids. Trace: due→claim→emit→handoff→acknowledged. Security: schedule owner/tenant and target capability bound by host.

E. WHAT THIS TOPIC DOES NOT OWN

№58 не владеет worker execution, business event semantics, workflow state machine, generic message transport, retry/circuit policy или user calendar product. Она владеет TIME RULE → DUE OCCURRENCE → DURABLE HANDOFF.

01. WHAT A SCHEDULER ACTUALLY DOES

ВЫЧИСЛЯЕТ NEXT DUE TIME И EMITS OCCURRENCE

SCHEDULE DEFINITIONone-time / recurring / delay / deadline.
NEXT RUNCompute in explicit timezone.
DUE SCAN / TIMERFind occurrences whose time has arrived.
CLAIMAtomically claim schedule occurrence.
OCCURRENCECreate idempotent scheduled occurrence.
HANDOFFQueue / event / workflow signal.
ADVANCECompute next_run / terminal state.
OBSERVELag, duplicate, misfire, failure.
Scheduler должен иметь собственную durable запись occurrence. Иначе crash между «увидели, что пора» и «поставили job в очередь» может потерять запуск.
02. SCHEDULE TYPES

НЕ ВСЁ ВРЕМЯ — CRON

ONE-TIME

At exact moment

«Запустить 5 сентября в 14:00 Europe/Riga».

RELATIVE DELAY

After duration

«Через 20 минут», «через 3 дня после события».

FIXED INTERVAL

Every N

Каждые 10 минут/6 часов. Семантика может быть fixed-rate или fixed-delay.

CALENDAR

Cron / recurrence

По будням в 09:00, первого числа, каждый понедельник.

DEADLINE

By time boundary

Escalate/expire/notify when deadline arrives.

WINDOW

Allowed execution window

Например, запускать в течение business hours, но не ночью.

Разные types требуют разных semantics. «Каждые 24 часа» не всегда равно «каждый день в 09:00 локального времени» из-за DST и timezone changes.
03. SCHEDULE CONTRACT

РАСПИСАНИЕ — VERSIONED CONTROL OBJECT

{
  "contract": "schedule.v1",
  "schedule_id": "SCH-...",
  "tenant_id": "tenant_A",
  "owner_ref": "user://...",
  "target": {
    "type": "JOB",
    "job_type": "source.sync",
    "payload_ref": "state://sync-source-42"
  },
  "timing": {
    "kind": "RECURRENCE",
    "rule": "FREQ=DAILY;BYHOUR=9;BYMINUTE=0",
    "timezone": "Europe/Riga"
  },
  "misfire": "SKIP|FIRE_ONCE|CATCH_UP",
  "max_lateness_s": 900,
  "status": "ACTIVE",
  "version": 3,
  "next_run_at": "...",
  "created_at": "...",
  "updated_at": "..."
}
CONTROL OBJECT

What must be explicit

  • owner / tenant;
  • target capability/job/event;
  • one-time or recurrence rule;
  • timezone;
  • start/end bounds;
  • misfire policy;
  • lateness tolerance;
  • schedule version;
  • status + next_run.

Natural-language request можно преобразовать в этот contract, но execution использует structured rule.

04. OCCURRENCE CONTRACT

РАСПИСАНИЕ И КОНКРЕТНЫЙ ЗАПУСК — НЕ ОДНО И ТО ЖЕ

{
  "occurrence_id": "OCC-...",
  "schedule_id": "SCH-...",
  "schedule_version": 3,
  "scheduled_for": "2026-09-01T09:00:00+03:00",
  "emitted_at": "2026-09-01T09:00:02+03:00",
  "idempotency_key":
    "schedule:SCH-...:2026-09-01T09:00:00+03:00",
  "target_ref": "job://...",
  "status": "EMITTED"
}
WHY OCCURRENCES

Audit and dedupe

Отдельная occurrence позволяет:

  • не дублировать один scheduled slot;
  • видеть пропущенные/запоздавшие fire;
  • re-drive конкретный запуск;
  • связать запуск с schedule version;
  • измерять scheduler lag;
  • отличать recurring definition от execution history.
05. AT-MOST-ONE LOGICAL OCCURRENCE

ДВА SCHEDULER INSTANCES НЕ ДОЛЖНЫ СОЗДАТЬ ДВА ОДИНАКОВЫХ ЗАПУСКА

INSTANCE A

Видит next_run_at ≤ now().

ATOMIC CLAIM / UNIQUE KEY

Claim schedule row или insert occurrence по unique (schedule_id, scheduled_for).

INSTANCE B

Получает conflict/no-op и не создаёт duplicate logical occurrence.

Exactly-once timer firing лучше строить как unique logical occurrence + idempotent downstream handoff, а не надеяться, что только один scheduler process когда-либо увидит due row.
06. FIXED RATE VS FIXED DELAY

«КАЖДЫЙ ЧАС» МОЖЕТ ОЗНАЧАТЬ ДВЕ РАЗНЫЕ ВЕЩИ

FIXED RATE

Clock-based

Запуски рассчитаны от календарной сетки: 10:00, 11:00, 12:00 независимо от длительности предыдущего run.

Подходит для polling/freshness schedules.

FIXED DELAY

Completion-based

Следующий запуск через N после завершения предыдущего: finished 10:17 → next 11:17.

Это уже требует знания completion state и ближе к workflow/job coordination.

Не маскировать fixed-delay cron expression-ом. Семантика должна быть явной в schedule contract.
07. TIMEZONES

UTC ДЛЯ ХРАНЕНИЯ, IANA TIMEZONE ДЛЯ CALENDAR INTENT

STORE

Instant in UTC

Computed next_run/current timestamps удобно хранить как absolute UTC instants.

RULE

Timezone-aware intent

Для «каждый день в 09:00 по Риге» хранить zone id вроде Europe/Riga, а не fixed +03:00.

RECOMPUTE

Calendar recurrence

Следующий occurrence вычисляется по timezone rules, учитывая DST/history changes.

Fixed offset и timezone — разные вещи. +02:00 не знает будущие переходы DST; Europe/Riga знает календарную зону.
08. DST

ЛОКАЛЬНОЕ ВРЕМЯ ИНОГДА НЕ СУЩЕСТВУЕТ ИЛИ СУЩЕСТВУЕТ ДВАЖДЫ

CaseProblemNeed explicit policy
Spring forwardНапример, 02:30 может не существовать.Skip / shift to next valid time / provider-defined behavior.
Fall back02:30 может произойти дважды.Fire once per local slot or per absolute instant.
Timezone rule changesGovernment changes DST/offset rules.Use maintained IANA timezone database.
User changes timezoneCalendar intent changes.Version schedule and recompute future runs.
Если schedules пользовательские, DST semantics должны быть тестами, а не «надеемся, библиотека как-нибудь решит».
09. MISFIRE POLICY

ЧТО ДЕЛАТЬ, ЕСЛИ СИСТЕМА ПРОСПАЛА РАСПИСАНИЕ

POLICY
DOWNTIME: 2H
BACKLOG
USE CASE
RISK
EXAMPLE
SKIP
missed runs ignored
none
Frequent polling where only next run matters.
May lose required execution.
Health refresh.
FIRE_ONCE
one immediate occurrence
small
Daily summary/reconcile.
Collapses multiple missed slots.
Daily report.
CATCH_UP
emit each missed slot
potentially large
Each interval semantically matters.
Backlog storm.
Billing periods.
EXPIRE
too-late occurrence discarded
none
Time-sensitive action useless later.
Need max lateness.
Reminder after deadline.
Misfire semantics — business property. Scheduler не должен всегда «догонять всё», иначе после двухчасового outage он может внезапно создать сотни jobs.
10. DOWNTIME RECOVERY

ПОСЛЕ RESTART НУЖНО RECONCILE DUE SCHEDULES

STARTScheduler process comes online.
SCAN DUEFind active next_run_at ≤ now.
CALCULATE MISSEDBased on recurrence + last occurrence.
APPLY MISFIREskip / fire once / catch up / expire.
EMIT UNIQUECreate occurrence idempotently.
ADVANCEPersist next_run.
Durable schedule registry делает restart обычным событием, а не потерей всех in-memory timers.
11. OVERLAPPING RUNS

ЧТО ЕСЛИ СЛЕДУЮЩЕЕ ВРЕМЯ НАСТУПИЛО, А ПРЕДЫДУЩАЯ JOB ЕЩЁ РАБОТАЕТ?

ALLOW

Parallel runs

Каждый occurrence независим; workers могут выполнять одновременно.

SKIP IF RUNNING

Singleton

Не создавать/не исполнять новый occurrence, если предыдущий active.

QUEUE NEXT

Serialize

Occurrence создаётся, но job ждёт previous completion.

COALESCE

Merge

Несколько missed/overlapping occurrences превращаются в один current refresh.

Overlap policy должна быть частью schedule/target contract. Для sync часто подходит coalesce/skip; для независимых billing periods — нет.
12. JITTER

НЕ ЗАПУСКАТЬ ВСЕ TENANTS РОВНО В 00:00

WITHOUT JITTER 1000 jobs at 09:00:00 WITH BOUNDED JITTER spread within allowed window
Jitter полезен для технических periodic jobs: sync, refresh, maintenance. Для user-facing exact-time reminders jitter использовать нельзя, если timing semantics обещают точное время.
13. SCHEDULER → QUEUE

ХОРОШИЙ DEFAULT: SCHEDULER СОЗДАЁТ JOB, WORKER ВЫПОЛНЯЕТ

SCHEDULER

Calculates due time and creates unique occurrence.

QUEUE / №57

Durably stores executable job and absorbs backlog.

WORKER

Executes under concurrency, retry, permission and resource controls.

Если scheduler сам делает HTTP calls, OCR, LLM inference или sync, он превращается в worker engine и становится трудно масштабируемым/восстанавливаемым.
14. SCHEDULER → EVENT

ИНогда ВРЕМЯ ДОЛЖНО СОЗДАТЬ EVENT, А НЕ JOB

JOB TARGET

Known executable work

«Каждые 15 минут синхронизировать source 42» → enqueue source.sync.

EVENT TARGET

Domain signal

«Наступил дедлайн договора» → emit domain event contract.deadline_reached; №42 decides which reactions/triggers follow.

Scheduler owns time boundary. Domain consequences belong to trigger/workflow/business logic.
15. WORKFLOW TIMERS

НЕ КАЖДЫЙ WAIT В WORKFLOW ДОЛЖЕН СТАТЬ ГЛОБАЛЬНЫМ SCHEDULE

№58 GLOBAL SCHEDULER

Independent schedule

Recurring reports, source sync, tenant maintenance, standalone reminder.

№68 WORKFLOW TIMER

Process-local wait

«Подождать 48 часов после отправки письма; если ответа нет — эскалировать». Timer is part of durable workflow history/state.

Оба могут использовать одну underlying timer service, но ownership разный: global schedule registry vs workflow execution state.
16. UPDATES & RACES

ЧТО ЕСЛИ USER ИЗМЕНИЛ РАСПИСАНИЕ В МОМЕНТ FIRING?

RaceRequired design
Schedule edited while due scan runsOptimistic version / row lock; occurrence stores schedule_version.
Schedule paused after occurrence emittedDefine whether already-emitted job remains valid; cancellation may target job separately.
Schedule deleted while worker runsDeletion stops future occurrences; existing execution follows explicit cancellation policy.
Timezone changedVersion schedule; recompute future next_run; old emitted occurrences retain old version.
Payload changedOccurrence binds payload/snapshot/reference version so execution is auditable.
Schedule versioning делает race conditions объяснимыми: любой occurrence можно связать с exact definition, которая была активна в момент fire.
17. PAUSE, RESUME, CANCEL

CONTROL PLANE ДОЛЖЕН БЫТЬ ЯВНЫМ

ACTIVE

Emit future occurrences

Normal scheduled state.

PAUSED

No new occurrences

Definition retained; resume policy determines next run.

EXPIRED

End reached

No future runs after end condition/date/count.

CANCELLED

Terminal stop

No future runs; historical occurrences remain auditable.

Pause/resume semantics need choice: resume from next future slot, fire missed once, or catch up. Не оставлять это неявным.
18. SECURITY & AUTHORITY

СОЗДАННОЕ ВЧЕРА РАСПИСАНИЕ НЕ ДОЛЖНО ОБХОДИТЬ СЕГОДНЯШНИЕ ПРАВА

CREATE

Who may schedule

Owner/principal authorized to create target schedule for tenant/resource.

EMIT

Scheduler authority

Scheduler can create occurrence but not automatically inherit all target credentials.

EXECUTE

Re-check sensitive action

Worker/tool evaluates current permission/policy where action can have external effect.

Schedule is not a perpetual bearer token. Permissions, approval expiry, resource state and policy may need re-evaluation at execution time.
19. LEADER ELECTION VS SHARED CLAIM

ДВА СПОСОБА ЗАПУСТИТЬ НЕСКОЛЬКО SCHEDULER INSTANCES

SINGLE LEADER

One active scheduler

Leader election гарантирует, что один instance вычисляет due jobs; standby takeover при failure.

MULTI-CONSUMER CLAIM

All may scan

Несколько instances atomically claim due rows/insert unique occurrences. Проще, если DB locking/unique constraints достаточны.

Для MVP с PostgreSQL часто проще multi-consumer claim / FOR UPDATE SKIP LOCKED + unique occurrence, чем строить отдельный leader-election subsystem.
20. SCHEDULER LOOP

ПРОСТОЙ DB-BASED ALGORITHM

loop every 1s:

  begin transaction

  due = SELECT schedules
        WHERE status='ACTIVE'
          AND next_run_at <= now()
        ORDER BY next_run_at
        FOR UPDATE SKIP LOCKED
        LIMIT 100

  for schedule in due:

      scheduled_for = schedule.next_run_at

      INSERT occurrence(
        schedule_id,
        schedule_version,
        scheduled_for,
        idempotency_key
      )
      ON CONFLICT(schedule_id, scheduled_for)
      DO NOTHING

      if inserted:
          enqueue_or_publish(occurrence)

      schedule.next_run_at =
          compute_next(schedule.rule, schedule.timezone)

  commit

  sleep
В production handoff в queue/broker нужно делать так, чтобы crash между occurrence insert и publish не терял работу: transactional outbox, same-DB queue или reconciliation of un-emitted occurrences.
21. TRANSACTIONAL HANDOFF

САМОЕ ОПАСНОЕ МЕСТО — МЕЖДУ «DUE» И «JOB DURABLE»

BAD

Mark then send

Advance next_run, crash before queue publish → occurrence lost.

ALSO BAD

Send then mark

Publish job, crash before advance → same occurrence may publish again.

GOOD

Durable occurrence + idempotency

Create unique occurrence transactionally; downstream emission is replayable/idempotent until acknowledged.

Это типичный distributed reliability seam. №69 позже соберёт такие patterns системно; scheduler должен уже проектироваться с replay-safe occurrence.
22. ACCURACY CLASSES

НЕ ВСЕ SCHEDULES ТРЕБУЮТ МИЛЛИСЕКУНДНОЙ ТОЧНОСТИ

ClassTypical lateness targetExamples
HUMAN REMINDERSeconds–minute depending product promise.User reminders/notifications.
BUSINESS BATCHMinutes.Daily report, sync, digest.
MAINTENANCEMinutes–hours.Cleanup, reindex, cache refresh.
WORKFLOW DEADLINEDomain-specific; often minutes.SLA escalation, approval timeout.
REAL-TIME CONTROLSub-second requirements.Usually not general application scheduler; use specialized realtime system.
Scheduler precision should match business value. Polling DB every 100 ms ради nightly sync — unnecessary operational cost.
23. OBSERVABILITY

СЛЕДИТЬ ЗА LAG, MISFIRE И OCCURRENCE DELIVERY

LAG

Fire latency

emitted_at - scheduled_for p50/p95/p99.

DUE

Overdue schedules

Количество active schedules с next_run_at сильно в прошлом.

MIS

Misfires

Skipped/caught-up/expired occurrences.

DUP

Duplicate occurrence

Conflicting occurrence insert/publish attempts.

HANDOFF

Emission status

Occurrence created but queue/event handoff pending/failed.

CALC

Rule errors

Invalid/uncomputable recurrence/timezone.

COUNT

Schedule volume

Active schedules/occurrences per tenant/type.

DRIFT

Clock/DB drift

Unexpected skew between scheduler nodes/time source where relevant.

24. TESTING

TIME LOGIC НУЖНО ТЕСТИРОВАТЬ С FAKE CLOCK

ONE-TIME

Exact fire

Before due = no occurrence; at/after due = one occurrence.

RECURRENCE

Next-run math

Daily/weekly/monthly rules across boundaries.

DST

Gap/fold

Spring/fall transitions for supported zones.

MISFIRE

Downtime

Advance fake clock by hours/days; verify skip/fire-once/catch-up.

DUP

Multi-instance

Two schedulers race; one logical occurrence created.

CRASH

Handoff seam

Crash before/after occurrence/publish; reconciliation recovers safely.

UPDATE

Version race

Edit/pause/cancel while due and verify bound semantics.

LOAD

Thundering herd

Thousands due simultaneously; jitter/backpressure/queue remain healthy.

Fake/controllable clock dramatically упрощает тесты scheduler-а. Не писать test suites, которые реально ждут час, чтобы проверить hourly recurrence.
25. FAILURE MODES

КАК SCHEDULER ЛОМАЕТСЯ

IN-MEMORY TIMERS ONLY
Restart процесса забывает pending schedules.
DURABLE REGISTRY
CRON = ALL TIME LOGIC
User timezones, misfires, updates и audit не моделируются.
STRUCTURED SCHEDULE
NO TIMEZONE
«09:00 local» хранится как offset и ломается на DST.
IANA ZONE
NO MISFIRE POLICY
После downtime случайно запускаются сотни catch-up jobs.
EXPLICIT POLICY
SCHEDULER EXECUTES WORK
Heavy jobs блокируют timer loop и recovery.
HANDOFF TO QUEUE
NO OCCURRENCE KEY
Two instances create duplicate logical runs.
UNIQUE SLOT KEY
ADVANCE BEFORE HANDOFF
Crash loses occurrence permanently.
DURABLE OCCURRENCE
AUTHORITY NEVER RECHECKED
Old schedule executes after permission/approval changed.
RECHECK AT EFFECT
MIDNIGHT HERD
All tenants hit queue/provider simultaneously.
JITTER / STAGGER
26. METRICS

ЧТО ИЗМЕРЯТЬ

LAG

Schedule Lag

scheduled_for → occurrence emitted.

MIS

Misfire Rate

% intended occurrences handled via misfire policy.

OVD

Overdue Schedules

Active schedules whose next_run is late beyond SLA.

DUP

Duplicate Logical Fire

Multiple downstream effects for one schedule slot. Target: zero.

HOF

Handoff Failure

Occurrences waiting/failed before queue/event delivery.

DST

Timezone Error

Incorrect calendar fires due to zone/rule handling.

ACT

Active Schedules

Count per tenant/type/timezone.

CUP

Catch-up Volume

Jobs emitted after outage and resulting pressure.

27. MVP IMPLEMENTATION

POSTGRESQL + ОДИН SCHEDULER LOOP МОЖЕТ ЗАКРЫТЬ 80%

schedules(
  schedule_id        uuid primary key,
  tenant_id          text,
  owner_ref          text,
  target_json        jsonb,
  timing_kind        text,
  timing_rule        text,
  timezone           text,
  misfire_policy     text,
  max_lateness_s     int,
  status             text,
  version            int,
  next_run_at        timestamptz,
  last_run_at        timestamptz,
  starts_at          timestamptz,
  ends_at            timestamptz,
  created_at         timestamptz,
  updated_at         timestamptz
)

occurrences(
  occurrence_id      uuid primary key,
  schedule_id        uuid,
  schedule_version   int,
  scheduled_for      timestamptz,
  emitted_at         timestamptz,
  handoff_status     text,
  target_ref         text,
  unique(schedule_id, scheduled_for)
)

scheduler process:
  scan due rows
  claim atomically
  insert occurrence
  handoff to DB queue
  compute/persist next_run
80% VALUE MVP

Simple reliable time layer

  • PostgreSQL schedule registry.
  • One-time + recurrence rules.
  • IANA timezone field.
  • Explicit misfire policy.
  • Unique occurrence per schedule slot.
  • Atomic due claim.
  • Handoff to №57 DB queue.
  • Pause/resume/cancel/versioning.
  • Startup reconciliation.
  • Lag/overdue/handoff metrics.

Dedicated timer service нужен позже, если millions of timers, sub-second precision, multi-region scale или DB scanning становится bottleneck.

28. WHEN TO UPGRADE

НЕ СТРОИТЬ DISTRIBUTED TIMER WHEEL ДО ПОЯВЛЕНИЯ ПРОБЛЕМЫ

SignalPotential upgrade
Millions of active schedulesPartitioned timing buckets / specialized scheduler service.
Sub-second timer precisionSpecialized timing infrastructure rather than periodic DB scans.
Multi-region active-active requirementsDistributed ownership/consensus/region affinity — see №69.
Complex workflow-local waitsDurable Workflow engine — see №68.
Huge fan-out at schedule boundariesQueue/broker capacity, jitter, admission control — №57/59/64.
29. PRACTICAL DECISION

СТОИТ ЛИ ДЕЛАТЬ ОТДЕЛЬНЫЙ КОМПОНЕНТ?

ВопросОтвет
Стоит ли реализовывать?Да, если time-based work является частью продукта/операций. Для пары системных periodic tasks обычного cron может хватить.
Separate Component?YES. Time calculation and durable occurrence emission — отдельная production responsibility.
Минимум 80% ценности?Schedule registry, timezone-aware recurrence, next_run, unique occurrence, misfire policy, queue handoff, pause/update/cancel, metrics.
Когда overkill?Distributed scheduler cluster для одного nightly maintenance script.
Trigger?Recurring tasks, reminders, delayed execution, deadlines, user-configurable schedules or time-triggered business events.
Как измерить uplift?Schedule lag, missed/duplicate occurrences, recovery after downtime, manual cron incidents, execution timeliness, operational simplicity.
Можно ли rule/tool/code вместо LLM-agent?Да, полностью. Natural language may help author a schedule, but canonical time semantics and emission must be deterministic code.
30. DESIGN RULES

ПРАВИЛА ДЛЯ РЕАЛЬНОЙ СИСТЕМЫ

RULE 01

Scheduler owns when

Execution belongs to queue/worker/workflow.

RULE 02

Persist schedules

Restart не должен стирать future timers.

RULE 03

Occurrence is first-class

Каждый time slot имеет durable unique logical identity.

RULE 04

Timezone is explicit

Calendar intent хранит IANA zone, не только UTC offset.

RULE 05

Misfire is explicit

Skip/fire-once/catch-up/expire — business choice.

RULE 06

Handoff is replayable

Crash between due and queue must not lose occurrence.

RULE 07

Version changes

Occurrence remembers schedule definition that produced it.

RULE 08

Recheck authority

Old schedule does not freeze permissions forever.

RULE 09

Use jitter selectively

Technical jobs can stagger; exact human-time commitments cannot.

31. FINAL MAP

TIME BECOMES A DURABLE SIGNAL — NOT A HIDDEN SLEEP()

USER / SYSTEM / ADMIN
        ↓
DEFINE SCHEDULE
  one-time
  delay
  interval
  calendar recurrence
  deadline
        ↓
STORE:
  owner
  tenant
  target
  rule
  timezone
  misfire policy
  version
  next_run
        ↓
TIME ADVANCES
        ↓
SCHEDULER FINDS DUE RULE
        ↓
ATOMIC CLAIM
        ↓
CREATE UNIQUE OCCURRENCE
  schedule_id
  schedule_version
  scheduled_for
  idempotency_key
        ↓
DURABLE HANDOFF
        ├─ №57 QUEUE / JOB
        ├─ №42 EVENT / TRIGGER
        └─ №68 WORKFLOW SIGNAL
        ↓
ADVANCE NEXT_RUN
        ↓
OBSERVE
  lag
  overdue
  misfire
  duplicate
  handoff failure

AFTER DOWNTIME:
  reconcile due schedules
  apply misfire policy
  emit only intended logical occurrences

CORE PRINCIPLE:

SCHEDULER DOES NOT
"DO THE JOB".

SCHEDULER MAKES TIME
A DURABLE, VERSIONED,
IDEMPOTENT SIGNAL.

QUEUE ANSWERS:
"WHAT IS WAITING?"

WORKER ANSWERS:
"WHO EXECUTES?"

SCHEDULER ANSWERS:
"WHEN SHOULD THE NEXT
LOGICAL OCCURRENCE EXIST?"

ECC RETROFIT / PRACTICAL HARNESS INTEGRATION

A. Related ECC ideas. Context-as-cache, scoped memory, lifecycle hooks, selective capabilities, feature flags, deterministic enforcement, provider-neutral adapters and eval-gated learning are applied only where relevant to №58 Scheduler.

B–E. Existing boundary and placement. The existing conceptual boundary, class PRODUCTION, default CONDITIONAL and owner Production Fabric remain authoritative. Runtime/control/data/offline placement is unchanged; durable state stays outside model context.

F–H. Hooks and contracts. Use bounded PRE_MODEL/POST_MODEL, PRE_TOOL/POST_TOOL, CHECKPOINT and TASK_COMPLETED events as applicable. Illustrative fields and canonical contracts are defined in NEW_CONTRACTS_SPEC.md; no universal schema is implied.

I–J. Security and evaluation. Host-side schema, permission, secret, budget, idempotency and audit checks take precedence over LLM output. Optional mechanisms require a feature flag and WITH/WITHOUT ablation; measure quality, acceptance, correction, latency, cost, escalations and severe errors.

K–L. Task profiles and cross-references. A TaskProfile selects the relevant skill, tool/context slice, memory scope and enforcement profile independently from FAST/STANDARD/DEEP. See cross-reference map, hook spec and ablation plan. Provider adapters remain outside the core.