Summary
henyey_app::maintainer logs WARN Maintenance took too long; consider increasing AUTOMATIC_MAINTENANCE_COUNT or performing manual database maintenance on the mainnet validator, with elapsed_ms steady in the 20–28 s range against a hardcoded 10 s threshold. It has fired 76 times on the current process (uptime 25d 19h).
The warning is a false positive introduced by the chunked-delete fix, and its remediation advice is backwards — following it makes elapsed_ms larger, not smaller.
No operational impact: the whole cycle runs off the ledger-close path in spawn_blocking_logged, the node has stayed Validating throughout with no ledger gaps, and RPC pruning is tracking normally (gap 466 vs bound 1580).
Evidence
Recent occurrences on the live validator (build 0ac84d42):
2026-07-24T19:21:26Z elapsed_ms=21295
2026-07-24T21:06:26Z elapsed_ms=21170
2026-07-25T15:21:27Z elapsed_ms=21589
2026-07-27T15:21:29Z elapsed_ms=23881
2026-07-27T16:21:31Z elapsed_ms=25777
Historical range on this process: 20 379 – 67 219 ms. 76 WARN lines total.
Config in configs/validator-mainnet-rpc.toml:
[rpc]
retention_window = 360
[maintenance]
enabled = true
period_secs = 900
count = 50000
Root cause
Two constants are in direct conflict.
1. The 10 s threshold (crates/app/src/maintainer.rs:220 and the duplicate at :269):
let elapsed = start.elapsed();
if elapsed > Duration::from_secs(10) {
warn!(elapsed_ms = elapsed.as_millis(),
"Maintenance took too long; consider increasing AUTOMATIC_MAINTENANCE_COUNT \
or performing manual database maintenance");
}
2. The deliberate per-chunk sleep (crates/app/src/maintainer.rs:343-348), added to stop maintenance from holding the WAL write lock and stalling ledger closes:
const MAINTENANCE_CHUNK_LEDGERS: u32 = 2;
const MAINTENANCE_CHUNK_PAUSE: Duration = Duration::from_millis(25);
delete_in_chunks sleeps MAINTENANCE_CHUNK_PAUSE between every chunk, and elapsed is measured around the whole of run_maintenance — so the sleeps are counted.
run_maintenance calls delete_in_chunks for five tables (maintainer.rs:469, 477, 481, 487, 491): SCP, ledger header, tx history, event, ledger close meta.
At period_secs = 900 and ~5 s/ledger, roughly 180 ledgers accrue per cycle, so each table walks ~180/2 = 90 chunks:
5 tables x 90 chunks x 25 ms = ~11.25 s of pure sleep
The structural sleep floor alone (~11 s) already exceeds the 10 s threshold, before a single row is deleted. The remaining ~10–17 s is real delete work against a 158 GB mainnet.db. So this warning cannot not fire in steady state on an RPC-enabled validator.
The advice is inverted
The message says "consider increasing AUTOMATIC_MAINTENANCE_COUNT". count is the per-table ledger budget passed to delete_in_chunks(count, ...). Raising it can only allow more chunks — hence more 25 ms sleeps and a larger elapsed_ms.
It is also already irrelevant here: count = 50000 is ~278x the ~180 ledgers/period actually produced. The loop exits early on Ok(0), so the budget is never the binding constraint — the sleep count is. An operator who follows the advice changes nothing at best.
Proposed fix
Pick one (a) and optionally (b):
(a) Make the threshold aware of the chunk floor. Either
- derive it from the design (
expected_chunks * MAINTENANCE_CHUNK_PAUSE * safety_factor), or
- express it as a fraction of the maintenance period (e.g. warn at
period / 3 = 300 s at period_secs=900) — the operationally meaningful question is "is maintenance at risk of not keeping up with its own period?", which 25 s clearly is not.
A flat 10 s predates the chunking change and no longer describes anything.
(b) Fix the remediation text. Increasing count is the wrong lever. If a cycle is genuinely slow the useful knobs are MAINTENANCE_CHUNK_LEDGERS (more work per lock acquisition) or MAINTENANCE_CHUNK_PAUSE (less idle time) — both of which trade against the WAL-lock-hold regression the chunking was added to fix.
Also worth folding the two duplicated threshold sites (:220, :269) into one named constant so they can't drift.
Not doing
No node code committed by the monitor. No validator impact; deploys remain held per #3702.
Filed by /monitor-tick 2801 at L63674835, build 0ac84d42.
Summary
henyey_app::maintainerlogsWARN Maintenance took too long; consider increasing AUTOMATIC_MAINTENANCE_COUNT or performing manual database maintenanceon the mainnet validator, withelapsed_mssteady in the 20–28 s range against a hardcoded 10 s threshold. It has fired 76 times on the current process (uptime 25d 19h).The warning is a false positive introduced by the chunked-delete fix, and its remediation advice is backwards — following it makes
elapsed_mslarger, not smaller.No operational impact: the whole cycle runs off the ledger-close path in
spawn_blocking_logged, the node has stayedValidatingthroughout with no ledger gaps, and RPC pruning is tracking normally (gap 466 vs bound 1580).Evidence
Recent occurrences on the live validator (build
0ac84d42):Historical range on this process: 20 379 – 67 219 ms. 76 WARN lines total.
Config in
configs/validator-mainnet-rpc.toml:Root cause
Two constants are in direct conflict.
1. The 10 s threshold (
crates/app/src/maintainer.rs:220and the duplicate at:269):2. The deliberate per-chunk sleep (
crates/app/src/maintainer.rs:343-348), added to stop maintenance from holding the WAL write lock and stalling ledger closes:delete_in_chunkssleepsMAINTENANCE_CHUNK_PAUSEbetween every chunk, andelapsedis measured around the whole ofrun_maintenance— so the sleeps are counted.run_maintenancecallsdelete_in_chunksfor five tables (maintainer.rs:469, 477, 481, 487, 491): SCP, ledger header, tx history, event, ledger close meta.At
period_secs = 900and ~5 s/ledger, roughly 180 ledgers accrue per cycle, so each table walks ~180/2 = 90 chunks:The structural sleep floor alone (~11 s) already exceeds the 10 s threshold, before a single row is deleted. The remaining ~10–17 s is real delete work against a 158 GB
mainnet.db. So this warning cannot not fire in steady state on an RPC-enabled validator.The advice is inverted
The message says "consider increasing AUTOMATIC_MAINTENANCE_COUNT".
countis the per-table ledger budget passed todelete_in_chunks(count, ...). Raising it can only allow more chunks — hence more 25 ms sleeps and a largerelapsed_ms.It is also already irrelevant here:
count = 50000is ~278x the ~180 ledgers/period actually produced. The loop exits early onOk(0), so the budget is never the binding constraint — the sleep count is. An operator who follows the advice changes nothing at best.Proposed fix
Pick one (a) and optionally (b):
(a) Make the threshold aware of the chunk floor. Either
expected_chunks * MAINTENANCE_CHUNK_PAUSE * safety_factor), orperiod / 3= 300 s atperiod_secs=900) — the operationally meaningful question is "is maintenance at risk of not keeping up with its own period?", which 25 s clearly is not.A flat 10 s predates the chunking change and no longer describes anything.
(b) Fix the remediation text. Increasing
countis the wrong lever. If a cycle is genuinely slow the useful knobs areMAINTENANCE_CHUNK_LEDGERS(more work per lock acquisition) orMAINTENANCE_CHUNK_PAUSE(less idle time) — both of which trade against the WAL-lock-hold regression the chunking was added to fix.Also worth folding the two duplicated threshold sites (
:220,:269) into one named constant so they can't drift.Not doing
No node code committed by the monitor. No validator impact; deploys remain held per #3702.
Filed by
/monitor-tick2801 at L63674835, build0ac84d42.