Skip to content

Shard spins at ~266% CPU and stops answering commands during sustained ingest (HSET + FT.* writes) #205

Description

@TinDang97

Summary

During a sustained Lunaris ingest, a single Moon shard entered a CPU spin
(~266%)
and stopped answering all commandsredis-cli PING blocks
indefinitely even though the TCP listener is still up — and made no further
persistence_tick checkpoint progress
for 40+ minutes. The only recovery was
SIGKILL. One pathological ingest payload wedged the entire shard, not just the
offending request.

Environment

  • moon release build, single shard (--shards 1)
  • flags: --appendonly no --save "" --disk-free-min-pct 1, --protected-mode no, port 6381
  • macOS (Darwin 24.6, arm64), host under heavy memory pressure at the time (swap ~87% full, ~2.5 GB free) — noting this as a possible contributing factor, not a confirmed cause.

Trigger

Ingesting the haystack for LongMemEval-S (longmemeval_s) question qid
1faac195 (dataset offset 57)
— ~46 sessions / ~494 turns, written as ~46
documents through Lunaris ingest_episode. Each document = one atomic_write
(MULTI) carrying HSET hydration docs plus FT vector + keyword index upserts
(FT.*). Offsets 0–56 ingested cleanly; the wedge reproduced on this specific
question.

Observed

  • Moon process pinned at ~266% CPU, sustained, for 40+ min (compute spin, not an idle wait).
  • redis-cli -p 6381 PING blocks — no reply — while the listener still accepts connections.
  • Last moon::shard::persistence_tick: Checkpoint complete log line ~40 min before kill, then total silence.
  • The Lunaris client was blocked on the in-flight command. Lunaris bounds every Moon command with a 10 s per-command response timeout (LUNARIS_MOON_OP_TIMEOUT), but no reply ever arrived — the connection stayed open and the server simply never responded, so the timeout's failure path didn't engage as expected against a spinning (vs. cleanly-dead) server.

Impact

A single degenerate ingest payload can wedge a whole shard indefinitely. There
is no server-side ceiling that bounds how long one request can hold the shard
spinning.

Repro pointer

LongMemEval-S longmemeval_s offset 57 (qid 1faac195), ingested through
Lunaris ingest_episode (chunk + RAPTOR community tree + vector/keyword FT.*
upserts). A minimal FT.*/HSET-only repro that drops the Lunaris layer is
pending — will follow once isolated (the host is mid-benchmark).

Questions / asks

  1. Any known FT.* / HNSW degenerate-input path that can spin (e.g. a
    pathological vector batch, an oversized field, or an index-rebuild loop)?
  2. Could sustained memory pressure push a shard into an unbounded alloc/GC spin
    rather than failing fast?
  3. Would a server-side per-command watchdog / CPU budget be feasible, so one
    request can't hold a shard spinning and unresponsive indefinitely?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions