Skip to content

memory: clean up active lock files on exit and termination signals #5485

Closed
Faris-as/servers
#1

Description

@Faris-as

Which server?

memory (@modelcontextprotocol/server-memory)

Server version

2.1.0

How did you run the server?

From a clone of this repository

Transport

stdio

Protocol era

Modern (2026-07-28)

MCP client and version

Claude Desktop / Autonomous Agent Orchestrator

Operating system and runtime

Linux / Node.js v24+

Server configuration

{
  "mcpServers": {
    "memory": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"]
    }
  }
}

Steps to reproduce

  1. Run @modelcontextprotocol/server-memory.
  2. Dispatch a mutation tool call (e.g. create_entities or add_observations) that acquires the lock via withFileLock.
  3. Terminate or stop the server process via SIGINT, SIGTERM, client disconnect, or container stop during the operation.
  4. Inspect the directory holding memory.jsonl.
  5. Attempt a subsequent write from another agent or container sharing the same graph file.

Expected behavior

The server should register signal handlers (SIGINT, SIGTERM) and exit cleanup hooks to remove any active lock file it currently holds, preventing orphaned lock files on abrupt shutdown.

Actual behavior

In Node.js, asynchronous finally blocks in withFileLock do not run when terminated by signals. Because src/memory registers no signal handlers (unlike src/everything/transports/stdio.ts), memory.jsonl.lock remains stranded on disk.
In multi-container or Docker environments where hostname !== os.hostname(), isLockOwnerDead returns false, forcing other agents to stall for up to 30–60 seconds before breaking the stale lock.
Additionally, in src/memory/Dockerfile, Node runs as PID 1 without STOPSIGNAL SIGINT, causing PID 1 to ignore SIGINT by default.

Already prototyped a fix?

Prompt for maintainer workflow:

"In src/memory/index.ts, track active lock files held by this process in an activeLocks map. On process exit and on SIGINT/SIGTERM, synchronously check if the lock file still contains our token, and if so, unlink it to avoid leaving stranded locks on abrupt shutdown. Add STOPSIGNAL SIGINT to src/memory/Dockerfile matching src/everything/Dockerfile. Add unit tests in file-lock.test.ts verifying active lock tracking and that cleanup leaves locks owned by another process intact."

Verification:

Before you submit

  • I searched existing issues and this is not a duplicate.
  • This is not a security vulnerability report.

Activity

  1. Faris-as commented on Nov 6, 2026

    @Faris-as
    Author

    Full implementation and tests are available on fork PR: Faris-as#1

  2. added
    bugSomething isn't working
    server-memoryReference implementation for the Memory MCP server - src/memory
    on Nov 10, 2026
  3. cliffhall commented on Nov 10, 2026

    @cliffhall
    Member

    Triage: Priority Low (total 5)

    • Severity 2: a lock left behind by a killed process stalls the next writer until the stale-lock check breaks it (sooner on the same host); nothing is lost and it clears on its own
    • Urgency 2: wanted eventually, nothing blocked on it
    • Bonuses: +1 bug label

    Board: Servers V2 (#43), Status Incoming, awaiting maintainer review (no milestone yet).

  4. added this to the v2.5.0 milestone on Nov 10, 2026
  5. sahiln27042008-blip commented on Nov 11, 2026

    @sahiln27042008-blip

    Hey @Faris-as @cliffhall — great catch in #5485 regarding orphaned .lock files in server-memory on abrupt container termination.

    In distributed systems, relying on async finally blocks during POSIX signal unwinding is a classic lifecycle trap—Node.js terminates before the event loop unwinds the async finally, leaving stale locks that cause persistent deadlocks across container restarts.

    We build DISTRIB, a deterministic simulation gate for agent systems, and we test exactly this: simulating pod evictions and SIGTERM interrupts mid-transaction to verify lock lease reclamation. We tested a synchronous signal handler wrapper with process.on('SIGINT') and heartbeat lease expirations (TTL-backed locks rather than purely manual unlinks) to make lock recovery completely crash-resilient.

    Happy to share our simulation harness or review your PR for free to ensure no edge-case lock leaks remain on abrupt client disconnects!

  6. self-assigned this
    on Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingserver-memoryReference implementation for the Memory MCP server - src/memoryv2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions