feat(journal): register per-user closeout job at day_rollover_hour
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -89,30 +89,65 @@ def _run_daily_prep_threadsafe(user_id: int) -> None:
|
||||
asyncio.run_coroutine_threadsafe(_do_daily_prep(user_id), _loop)
|
||||
|
||||
|
||||
async def _do_closeout(user_id: int) -> None:
|
||||
try:
|
||||
tz_str = await get_user_timezone(user_id)
|
||||
tz = _resolve_tz(tz_str)
|
||||
now = datetime.datetime.now(tz)
|
||||
# We just rolled into a new day in user-local time. The day that
|
||||
# just ended is yesterday's calendar date regardless of whether
|
||||
# rollover_hour is 0 or 4 — APScheduler fires precisely at the
|
||||
# configured hour so no clock-skew correction is needed.
|
||||
yesterday = now.date() - datetime.timedelta(days=1)
|
||||
from fabledassistant.services.journal_closeout import run_for_user
|
||||
await run_for_user(user_id=user_id, yesterday=yesterday)
|
||||
except Exception:
|
||||
logger.exception("Closeout failed for user %d", user_id)
|
||||
|
||||
|
||||
def _run_closeout_threadsafe(user_id: int) -> None:
|
||||
if _loop is None:
|
||||
return
|
||||
asyncio.run_coroutine_threadsafe(_do_closeout(user_id), _loop)
|
||||
|
||||
|
||||
async def update_user_schedule(user_id: int) -> None:
|
||||
"""Add or replace this user's daily-prep job using their current config."""
|
||||
"""Add or replace this user's daily-prep + closeout jobs from current config."""
|
||||
if _scheduler is None:
|
||||
return
|
||||
job_id = f"journal_prep_{user_id}"
|
||||
if _scheduler.get_job(job_id):
|
||||
_scheduler.remove_job(job_id)
|
||||
|
||||
config = await get_journal_config(user_id)
|
||||
if not config.get("prep_enabled", True):
|
||||
return
|
||||
|
||||
tz_str = await get_user_timezone(user_id)
|
||||
tz = _resolve_tz(tz_str)
|
||||
prep_hour = int(config.get("prep_hour", 5))
|
||||
prep_minute = int(config.get("prep_minute", 0))
|
||||
|
||||
_scheduler.add_job(
|
||||
_run_daily_prep_threadsafe,
|
||||
trigger=CronTrigger(hour=prep_hour, minute=prep_minute, timezone=tz),
|
||||
args=[user_id],
|
||||
id=job_id,
|
||||
replace_existing=True,
|
||||
)
|
||||
# ── Prep job ──────────────────────────────────────────────────────────
|
||||
prep_job_id = f"journal_prep_{user_id}"
|
||||
if _scheduler.get_job(prep_job_id):
|
||||
_scheduler.remove_job(prep_job_id)
|
||||
if config.get("prep_enabled", True):
|
||||
prep_hour = int(config.get("prep_hour", 5))
|
||||
prep_minute = int(config.get("prep_minute", 0))
|
||||
_scheduler.add_job(
|
||||
_run_daily_prep_threadsafe,
|
||||
trigger=CronTrigger(hour=prep_hour, minute=prep_minute, timezone=tz),
|
||||
args=[user_id],
|
||||
id=prep_job_id,
|
||||
replace_existing=True,
|
||||
)
|
||||
|
||||
# ── Closeout job ──────────────────────────────────────────────────────
|
||||
closeout_job_id = f"journal_closeout_{user_id}"
|
||||
if _scheduler.get_job(closeout_job_id):
|
||||
_scheduler.remove_job(closeout_job_id)
|
||||
if config.get("closeout_enabled", True):
|
||||
rollover_hour = int(config.get("day_rollover_hour", 4))
|
||||
_scheduler.add_job(
|
||||
_run_closeout_threadsafe,
|
||||
trigger=CronTrigger(hour=rollover_hour, minute=0, timezone=tz),
|
||||
args=[user_id],
|
||||
id=closeout_job_id,
|
||||
replace_existing=True,
|
||||
)
|
||||
|
||||
|
||||
async def _register_all_user_jobs() -> None:
|
||||
|
||||
Reference in New Issue
Block a user