fix(cron): persist channel_meta and session_key across reloads

Without writing these fields into jobs.json, cron jobs created in a
Slack thread lost their thread_ts (and original session_key) after the
service was reloaded, so reminders fired into the channel root.

Made-with: Cursor
This commit is contained in:
Xubin Ren
2026-04-27 12:45:00 +08:00
committed by Xubin Ren
parent 6eb178113e
commit 4801f54f5b
2 changed files with 39 additions and 0 deletions
+8
View File
@@ -109,6 +109,12 @@ class CronService:
deliver=j["payload"].get("deliver", False),
channel=j["payload"].get("channel"),
to=j["payload"].get("to"),
channel_meta=(
j["payload"].get("channelMeta")
or j["payload"].get("channel_meta")
or {}
),
session_key=j["payload"].get("sessionKey") or j["payload"].get("session_key"),
),
state=CronJobState(
next_run_at_ms=j.get("state", {}).get("nextRunAtMs"),
@@ -210,6 +216,8 @@ class CronService:
"deliver": j.payload.deliver,
"channel": j.payload.channel,
"to": j.payload.to,
"channelMeta": j.payload.channel_meta,
"sessionKey": j.payload.session_key,
},
"state": {
"nextRunAtMs": j.state.next_run_at_ms,
+31
View File
@@ -65,6 +65,37 @@ def test_add_job_preserves_channel_meta_and_session_key(tmp_path) -> None:
assert reloaded.payload.session_key == "slack:C123:1234567890.123456"
@pytest.mark.asyncio
async def test_channel_meta_and_session_key_survive_store_reload(tmp_path) -> None:
store_path = tmp_path / "cron" / "jobs.json"
service = CronService(store_path)
await service.start()
meta = {"slack": {"thread_ts": "1234567890.123456", "channel_type": "channel"}}
try:
job = service.add_job(
name="thread test",
schedule=CronSchedule(kind="every", every_ms=60_000),
message="hello",
deliver=True,
channel="slack",
to="C123",
channel_meta=meta,
session_key="slack:C123:1234567890.123456",
)
finally:
service.stop()
raw = json.loads(store_path.read_text(encoding="utf-8"))
payload = raw["jobs"][0]["payload"]
assert payload["channelMeta"] == meta
assert payload["sessionKey"] == "slack:C123:1234567890.123456"
reloaded = CronService(store_path).get_job(job.id)
assert reloaded is not None
assert reloaded.payload.channel_meta == meta
assert reloaded.payload.session_key == "slack:C123:1234567890.123456"
@pytest.mark.asyncio
async def test_execute_job_records_run_history(tmp_path) -> None:
store_path = tmp_path / "cron" / "jobs.json"