Skip to content

maintainer: 'Maintenance took too long' WARN fires structurally — 10s threshold is below the chunk-pause floor, and its advice is inverted #3754

Description

@tomerweller

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcrate:apphenyey-app cratelowLow severity

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions