Skip to content

bm reindex --full completes its work but never exits, pinning one CPU core #1322

Description

@benjaminfrombe

Summary

bm reindex --full finishes all of its work but never exits. The process stays alive and pins exactly one CPU core indefinitely, doing zero syscalls. It has to be killed manually.

Environment

  • Basic Memory 0.23.0 (ghcr.io/basicmachines-co/basic-memory:latest, FastMCP 4.0.0b1)
  • Docker, SQLite backend
  • Semantic search enabled: fastembed / bge-small-en-v1.5, sqlite-vec vector index
  • Corpus: 573 markdown files (3.6 MB), 575 entities, 174 observations, 994 relations, 14440 vector chunks

Steps to reproduce

basic-memory reindex --full

Expected

The command completes its work and exits.

Actual

All work completes successfully:

  • embeddings: 14440 of 14440 chunks embedded
  • search_index: 1743 rows (= 575 entities + 174 observations + 994 relations, consistent)
  • log line: watch_service:handle_changes:342 - Event-index file change processing completed, processed_files=573, failed_files=0, skipped_files=0, total_indexed_files=6303, duration_ms=1721

After that the process keeps running at ~100% CPU (one full core) with no further progress and no further log output.

Evidence that it is a spin loop, not remaining work

/proc/<pid>/io sampled several minutes apart is byte for byte identical, while the process continues to accrue CPU time:

sample 1: rchar: 2416681816 wchar: 928888478 syscr: 571216 syscw: 388900 read_bytes: 692224 write_bytes: 866467840
sample 2: rchar: 2416681816 wchar: 928888478 syscr: 571216 syscw: 388900 read_bytes: 692224 write_bytes: 866467840

Zero syscalls, zero reads, zero writes, yet CPU time keeps accumulating at ~101% (measured as ~1012 utime+stime ticks per 10 seconds).

Process state at that point:

  • 38 threads
  • main thread wchan = do_epoll_wait (asyncio loop idle)
  • open fds: 15x memory.db, 5x memory.db-wal, 1x memory.db-shm, plus the log file and two sockets/pipes

Database counters are frozen during the whole period:

chunks 14440 | embedded 14440 | index 1743

So the main thread is parked in the event loop while some other thread spins.

Workaround

kill -TERM <pid> terminates it cleanly. PRAGMA integrity_check returns ok afterwards and all counters are intact, which supports the conclusion that the work really was finished.

Note on a separate observation

Mentioned only so the CPU usage during the run is not confused with the spin loop after completion, and in case the numbers are useful.

The embedding phase itself runs at roughly 570 chunks/minute at ~570% CPU on 8 cores (fastembed / bge-small-en-v1.5). I tried tuning it and found no measurable effect:

semantic_embedding_batch_size semantic_embedding_request_concurrency throughput
2 4 ~570 chunks/min
32 1 ~570 chunks/min
32 4 ~570 chunks/min

So neither batch size nor request concurrency appears to influence embedding throughput on this setup. If those knobs are expected to matter, they may not be reaching the fastembed call path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions