diff --git a/.github/workflows/status.yml b/.github/workflows/status.yml index 218792d..2fcd058 100644 --- a/.github/workflows/status.yml +++ b/.github/workflows/status.yml @@ -1,16 +1,22 @@ name: status # Rebuilds the public status page on GitHub Pages from the live records in S3 -# and the monthly AWS Budget. It runs after the 10:15 deadline check and after -# the 14:30 scoring run (Berlin; the cron times are UTC and land after both in -# summer and winter time), and whenever the page code changes on main. +# and the monthly AWS Budget, and whenever the page code changes on main. +# +# Hourly from 07:17 to 18:17 UTC. That covers the 09:00 forecast, the 10:15 +# deadline and the 14:30 scoring run (Berlin), including scoring's up to 3 +# hours of waiting for late prices, in summer and winter time. GitHub often +# starts scheduled runs hours late, so with one run an hour a late start +# costs about an hour of staleness instead of half a day. Minute 17 avoids +# the busy top of the hour. Each build is a handful of S3 reads and a free +# Budgets API call, and Actions minutes are free on a public repo. +# # GitHub pauses scheduled workflows after 60 days without commits; a manual # run (workflow_dispatch) starts them again. on: schedule: - - cron: "30 9 * * *" - - cron: "15 14 * * *" + - cron: "17 7-18 * * *" push: branches: [main] paths: diff --git a/README.md b/README.md index 6484dad..a711bcd 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ misses a promise, and keeps the evidence behind every number it publishes. **[Live status page](https://dhamsey3.github.io/voltcast/)**: the latest forecast against the cleared price, the running error, what's deployed and the AWS bill. -It's rebuilt twice a day from the service's own records, and the data behind it +It's rebuilt hourly during the day from the service's own records, and the data behind it is at [`status.json`](https://dhamsey3.github.io/voltcast/status.json). ## Why this problem @@ -149,8 +149,8 @@ Berlin. ## Operating it - [Status page](https://dhamsey3.github.io/voltcast/): rebuilt by the - [status workflow](.github/workflows/status.yml) after the 10:15 deadline check and after - scoring, with a read-only role that sees only published results ([ADR 6](docs/adr/0006-status-page.md)) + [status workflow](.github/workflows/status.yml) hourly from 07:17 to 18:17 UTC, with a + read-only role that sees only published results ([ADR 6](docs/adr/0006-status-page.md)) - [Runbook](docs/runbook.md): what each alarm means and what to do - [Incidents](docs/incidents/README.md): every missed promise, written up - [Decisions](docs/adr/): ADRs 1 to 6 diff --git a/docs/adr/0006-status-page.md b/docs/adr/0006-status-page.md index 53c8919..72b5b4f 100644 --- a/docs/adr/0006-status-page.md +++ b/docs/adr/0006-status-page.md @@ -43,3 +43,12 @@ the whole service runs at about 1 USD a month. run starts them again. - Only live forecasts appear. The backfill replay stays in `voltcast report` and the README, so the live record is never mixed with hindsight. + +## Update, 2026-10-19: hourly rebuilds + +In the first days live, GitHub started the two scheduled runs 3 to 4 hours +late (09:30 UTC ran at about 13:20, 14:15 at about 17:20). For most of each +morning the page didn't show that day's forecast. The workflow now runs +hourly from 07:17 to 18:17 UTC, so a late start costs about an hour. The +extra runs are free: a handful of S3 reads, a free Budgets API call, and +free Actions minutes on a public repo. diff --git a/src/voltcast/page.py b/src/voltcast/page.py index c69e658..4e5dc6e 100644 --- a/src/voltcast/page.py +++ b/src/voltcast/page.py @@ -507,7 +507,7 @@ def render(status: dict) -> str:

Tomorrow's German power prices, forecast and graded every day

Each morning voltcast publishes a price for every quarter-hour of tomorrow's {_e(status["region"])} day-ahead auction, before bidding closes at 12:00. That afternoon it scores itself against the prices that cleared. - This page is rebuilt from the service's own records twice a day.

+ This page is rebuilt from the service's own records every hour during the day.

Updated {_e(_when(status["generated_at"]))} · status.json · Source and design