Files
molecule-ai-plugin-scheduler/.gitea/workflows/ci.yml
T
hongming 5196de0836
meta-ci-advisory / meta (advisory) (pull_request) Successful in 6s
ci / validate (pull_request) Successful in 18s
ci / validate (push) Successful in 17s
fix(scheduler): regenerate daemon from SDK 0.5.6 — tick no longer freezes on a hung fire
molecule-core's ephemeral-CP e2e failed with "Scheduler never fired
'e2e-fire-local' within 360s". The daemon this plugin ships (generated from
SDK 0.5.5) delivers each due self-turn synchronously inside the tick loop and
writes its heartbeat only AFTER that loop. A self-turn is a blocking A2A
message/send with a 600s default timeout, so when the agent was settling the
tick never returned:

  target   health: {"armed": 1, "errors": {}, "last_tick": "21:16:57"}  <- probed 21:23:19
  sibling  health: {"armed": 0, "errors": {}, "last_tick": "21:23:15"}  <- still ticking

last_tick froze 2s after arming and never advanced for 6m22s while sibling
daemons kept ticking, and health kept reporting a healthy-looking armed:1 /
errors:{} the whole time. The process was alive-but-hung, so the runtime
supervisor never restarted it: a tenant's schedules stop firing until the
container is replaced.

SDK 0.5.6 fixes this at the SSOT (scaffold commit ab21b58, released via
molecule-ai-sdk PRs #173/#187): delivery is DECOUPLED from ticking. The tick
only enqueues due fires and always advances last_tick; a serial background
worker delivers, with a watchdog that cancels and RE-QUEUES a wedged delivery
so at-least-once holds (the earlier bounded-timeout idea was rejected upstream
because a short deadline cannot tell a hung agent from a healthy long turn,
and advancing on timeout silently drops the fire).

  - scheduler.py regenerated from the 0.5.6 scaffold (the only gated file that
    changed; trigger_schedule.py and channel_sdk.py are byte-identical).
  - ci.yml SDK_VERSION 0.5.5 -> 0.5.6 so the drift gate regenerates from the
    version that carries the fix.
  - plugin.yaml 0.2.0 -> 0.2.1.
  - tests/test_scaffold.py synced from the 0.5.6 scaffold. The instance copy
    still exercised `scheduler.run_once`, which no longer exists (it is now
    SchedulerDaemon.tick), so it would not even import against the new daemon.
    The synced suite carries the regression guards:
    test_hung_delivery_does_not_freeze_the_tick_loop,
    test_watchdog_requeues_a_wedged_delivery,
    test_healthy_long_turn_completes_and_advances_without_error,
    test_poke_whose_delivery_fails_is_requeued_not_dropped.

Verified locally against the published 0.5.6 wheel, running this repo's own CI
steps: manifest valid, DRIFT-GATE OK (byte-identical), 16/16 tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 19:11:06 -07:00

41 lines
1.8 KiB
YAML

name: ci
on: [push, pull_request]
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.11"
# No `cache: pip` — this plugin ships no requirements.txt/pyproject.toml
# (it vendors channel_sdk and installs the authoring SDK ad-hoc below),
# and setup-python's pip cache hard-fails without a deps file to hash.
- name: Install authoring SDK (scaffold SSOT)
# This plugin is a materialized instance of the SDK trigger scaffold, so
# `validate` and the drift gate need the SDK. Install it from its git
# RELEASED-wheel pin: bumped to sdk 0.5.5, which adds the RFC-#8
# schedule_name outcome correlation to the trigger scaffold (drift gate
# byte-identical vs the 0.5.5 wheel). Bump SDK_VERSION (and regenerate
# this plugin) whenever the SDK trigger scaffold changes.
env:
SDK_VERSION: 0.5.6
run: |
# --extra-index-url (not --index-url): the Gitea registry hosts only
# molecule packages; deps (pyyaml) must still resolve from PyPI.
python -m pip install "molecule-ai-sdk==${SDK_VERSION}" \
--extra-index-url https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/
- name: Manifest validation
run: python -m molecule_plugin validate plugin .
- name: SSOT drift gate (daemon logic == SDK scaffold)
run: python scripts/check_scaffold_drift.py
- name: Daemon unit tests
run: python -m unittest discover -s tests -v