Skip to content

perf(storage): debounce saves via async_delay_save (PERF-3)#614

Merged
tempus2016 merged 1 commit into
mainfrom
perf/debounced-saves
Jun 26, 2026
Merged

perf(storage): debounce saves via async_delay_save (PERF-3)#614
tempus2016 merged 1 commit into
mainfrom
perf/debounced-saves

Conversation

@tempus2016

Copy link
Copy Markdown
Owner

PERF-3 — Debounce storage saves

A single TaskMate operation frequently calls async_save 2-4× (mutate a record → award points → refresh), each serialising the entire _data blob to disk.

Fix

Route async_save through Store.async_delay_save(lambda: _data, 1.0s), which coalesces rapid saves into one debounced disk write. The 1 s window fully absorbs the within-operation duplicates while keeping any crash-loss window tiny.

  • storageasync_save now debounced; new async_save_now() for immediate writes; the data_version bump still happens per logical save, so PERF-2 cache invalidation stays correct.
  • coordinatorasync_shutdown calls await storage.async_save_now() so an entry unload/reload flushes any pending write (HA already flushes delayed saves on full shutdown; this covers reloads too).
  • tests/conftestFakeStore.async_delay_save writes through immediately for deterministic test persistence.

Verification

  • test_save_debounce.py: async_save uses async_delay_save (no direct write) and bumps version each call; async_save_now writes through; async_shutdown flushes.
  • Storage / integration / backup / coordinator / data-version suites green; Ruff clean. (The 3 TestOneShotChores failures in mixed runs are the documented pre-existing order-pollution — they fail identically on the unchanged tree and pass in isolation.)
  • Live on ha-dev: add_points +5 → waited out the debounce → full HA restart → balance persisted (63), proving the delayed write lands; reverted.

Part of the v4.3.1 audit fix campaign. No version bump / release.

A single TaskMate operation frequently calls async_save 2-4x (mutate
record, award points, refresh), each serialising the whole _data blob
to disk. Route async_save through Store.async_delay_save so those
collapse into one debounced write (1s window). HA flushes pending
delayed saves on shutdown; async_shutdown also forces a flush.

- storage: async_save -> async_delay_save(lambda: _data, 1.0s);
  new async_save_now() for immediate writes; version still bumps per
  logical save (keeps PERF-2 cache invalidation correct)
- coordinator.async_shutdown: await storage.async_save_now() so an
  entry unload/reload can't drop the last mutation
- tests/conftest FakeStore: async_delay_save writes through immediately
  for deterministic test persistence

Tests: test_save_debounce.py (delay-save used, no direct write;
save_now writes through; per-save version bump; shutdown flush).
Storage/integration/backup suites green; live-verified on ha-dev:
add_points +5 survived a full HA restart (debounced write landed),
then reverted.
@github-actions github-actions Bot added backend Python integration code tests Test suite labels Jun 26, 2026
@tempus2016 tempus2016 merged commit 24dab92 into main Jun 26, 2026
10 checks passed
@tempus2016 tempus2016 deleted the perf/debounced-saves branch June 26, 2026 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Python integration code tests Test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant