The Go server now runs the bank sync by itself on a schedule, defaulting to once a day. Until now the sync only ran when someone opened /sync-bank.
Go only, on purpose. The legacy Python app is being phased out and its multi-worker setup would need a cross-process lock for this. This is recorded in CLAUDE.md under "Deliberately Go-only features" and in a comment in legacy/app.py.
Behaviour
SYNC_SCHEDULE: comma-separated HH:MM times, default 04:00. off disables it. An invalid value stops the server at startup with an error.
SYNC_TZ: zone the times are read in, default Europe/Prague. The binary embeds the zone database, since the Alpine image has none.
Each scheduled run does what /sync-bank does: sync, infer, flush cache. It has a 10-minute timeout and logs the outcome.
Nothing runs at startup.
Manual and scheduled runs share one lock. A second request while one is running gets "a sync is already running". This also closes the existing gap where two overlapping manual runs could append the same rows.
The page footer shows the last sync since the server started (time, trigger, ok/FAILED) and the next scheduled run.
Deployment notes
It is on by default at 04:00 Europe/Prague once this image is deployed. Set SYNC_SCHEDULE=off to disable.
The schedule runs per process: the deployment must stay at one replica.
A local make web-go with real credentials also syncs at the scheduled time unless SYNC_SCHEDULE=off.
Without FIO_API_TOKEN_NEW / FIO_API_TOKEN_OLD it scrapes the transparent-account pages, as the manual sync does today.
Testing
New unit tests: schedule parsing, next-run calculation (including both DST switch days), run loop cancellation, runner status and busy handling, config loading, footer rendering.
make go-test-all (with -race) and make test pass. No new dependencies; no change to the JSON API or parity fixtures.
Live: server started with a schedule two minutes ahead ran one real scheduled sync (1 new transaction appended, 1 row inferred) and the footer updated.
Startup with SYNC_SCHEDULE=25:00 and with an unknown SYNC_TZ exits with a clear error; off logs that the schedule is disabled.
In the built container the schedule resolves to 04:00+02:00, confirming the embedded zone data works.
Not exercised: the "already running" path against a real sync (covered by a unit test only), and golangci-lint, which is still broken locally (T7).
## What
The Go server now runs the bank sync by itself on a schedule, defaulting to once a day. Until now the sync only ran when someone opened `/sync-bank`.
**Go only, on purpose.** The legacy Python app is being phased out and its multi-worker setup would need a cross-process lock for this. This is recorded in `CLAUDE.md` under "Deliberately Go-only features" and in a comment in `legacy/app.py`.
## Behaviour
- `SYNC_SCHEDULE`: comma-separated `HH:MM` times, default `04:00`. `off` disables it. An invalid value stops the server at startup with an error.
- `SYNC_TZ`: zone the times are read in, default `Europe/Prague`. The binary embeds the zone database, since the Alpine image has none.
- Each scheduled run does what `/sync-bank` does: sync, infer, flush cache. It has a 10-minute timeout and logs the outcome.
- Nothing runs at startup.
- Manual and scheduled runs share one lock. A second request while one is running gets "a sync is already running". This also closes the existing gap where two overlapping manual runs could append the same rows.
- The page footer shows the last sync since the server started (time, trigger, ok/FAILED) and the next scheduled run.
## Deployment notes
- It is **on by default** at 04:00 Europe/Prague once this image is deployed. Set `SYNC_SCHEDULE=off` to disable.
- The schedule runs per process: the deployment must stay at one replica.
- A local `make web-go` with real credentials also syncs at the scheduled time unless `SYNC_SCHEDULE=off`.
- Without `FIO_API_TOKEN_NEW` / `FIO_API_TOKEN_OLD` it scrapes the transparent-account pages, as the manual sync does today.
## Testing
- New unit tests: schedule parsing, next-run calculation (including both DST switch days), run loop cancellation, runner status and busy handling, config loading, footer rendering.
- `make go-test-all` (with `-race`) and `make test` pass. No new dependencies; no change to the JSON API or parity fixtures.
- Live: server started with a schedule two minutes ahead ran one real scheduled sync (1 new transaction appended, 1 row inferred) and the footer updated.
- Startup with `SYNC_SCHEDULE=25:00` and with an unknown `SYNC_TZ` exits with a clear error; `off` logs that the schedule is disabled.
- In the built container the schedule resolves to 04:00+02:00, confirming the embedded zone data works.
- Not exercised: the "already running" path against a real sync (covered by a unit test only), and `golangci-lint`, which is still broken locally (T7).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The Go server now runs sync -> infer -> flush-cache by itself at the
times in SYNC_SCHEDULE (comma-separated HH:MM, default 04:00, "off"
disables), read in SYNC_TZ (default Europe/Prague). Nothing runs at
startup; an invalid value stops the server with an error.
- internal/scheduler: time-of-day parsing, Next, and the run loop
- banksync.Runner: one lock shared by /sync-bank and the scheduler so
runs never overlap, plus the status of the last run
- footer shows the last sync since start and the next scheduled run
- binary embeds time/tzdata because the Alpine image has no zone data
Deliberately not implemented in the legacy Python app, which is being
phased out; recorded in CLAUDE.md under "Deliberately Go-only features".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kacerr
merged commit d5da993690 into main2026-10-08 12:27:14 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
The Go server now runs the bank sync by itself on a schedule, defaulting to once a day. Until now the sync only ran when someone opened
/sync-bank.Go only, on purpose. The legacy Python app is being phased out and its multi-worker setup would need a cross-process lock for this. This is recorded in
CLAUDE.mdunder "Deliberately Go-only features" and in a comment inlegacy/app.py.Behaviour
SYNC_SCHEDULE: comma-separatedHH:MMtimes, default04:00.offdisables it. An invalid value stops the server at startup with an error.SYNC_TZ: zone the times are read in, defaultEurope/Prague. The binary embeds the zone database, since the Alpine image has none./sync-bankdoes: sync, infer, flush cache. It has a 10-minute timeout and logs the outcome.Deployment notes
SYNC_SCHEDULE=offto disable.make web-gowith real credentials also syncs at the scheduled time unlessSYNC_SCHEDULE=off.FIO_API_TOKEN_NEW/FIO_API_TOKEN_OLDit scrapes the transparent-account pages, as the manual sync does today.Testing
make go-test-all(with-race) andmake testpass. No new dependencies; no change to the JSON API or parity fixtures.SYNC_SCHEDULE=25:00and with an unknownSYNC_TZexits with a clear error;offlogs that the schedule is disabled.golangci-lint, which is still broken locally (T7).🤖 Generated with Claude Code