9 Commits

Author SHA1 Message Date
Matt Isenhower
ef24b6183a Retain a combined history of the latest 50 updater runs 2026-09-13 12:54:30 -07:00
Matt Isenhower
6555ff709b Add persistent automatic scheduling toggle to admin panel 2026-09-13 10:06:31 -07:00
Matt Isenhower
5deac8c8cb Use Browser binding for screenshots and local Wrangler testing 2026-09-07 18:06:15 -07:00
Matt Isenhower
a1e934d0bd Improve readability of test setup and assertions 2026-09-07 17:52:50 -07:00
Matt Isenhower
f9154a1dfb Show live and retained run logs in the admin panel 2026-09-07 13:42:25 -07:00
Matt Isenhower
01d2b87335 Persist manual data and social runs for background execution 2026-09-07 13:37:19 -07:00
Matt Isenhower
1b430d172a Simplify hourly scheduling and serialize all updater runs 2026-09-07 13:00:14 -07:00
Matt Isenhower
9258447df7 Run the social posters in the Worker after the updaters
The Scheduler's hourly alarm now runs two jobs in order, updaters then
posters, matching the container; a failure in either schedules the
retry. POST /post runs the posters by hand and wake?job=posters through
the alarm. The posters read process.env, which Workers populate from the
bindings: SITE_URL and CLOUDFLARE_ACCOUNT_ID are vars, the Browser
Rendering token and the social credentials are secrets. Without social
credentials the posters only render and save the public images, which is
the shadow mode until cutover.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 19:06:48 -07:00
Matt Isenhower
188d9cb504 Run the updaters in a Cloudflare Worker
workers/updater runs src/app/updater, the same code npm run splatnet runs
locally, against the Worker's R2 bindings through BucketStorage. The
Scheduler Durable Object from the proof of concept owns when the run
happens: an alarm at :00:10 that re-arms itself, with retries after a
failed run; the only cron trigger is a minute-30 watchdog that re-arms a
lost alarm. Operator endpoints (/run, /wake, /arm, /status) are behind a
bearer token. Handlers and the Durable Object are wrapped with
@sentry/cloudflare so the updaters' @sentry/core reports are delivered
when SENTRY_DSN is set.

updateAll() now returns a per-updater result (name, ok, duration, error)
that both the local runner and the Worker can report on, and the SplatNet
client reads its user agent lazily since Workers populate process.env
from the bindings.

Deployed in shadow mode against the dev bucket: a full run of all eight
updaters on Cloudflare matched production's data semantically within the
same hour, and steady-state runs take about seven seconds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 11:23:49 -07:00