cocoindex-io / cocoindex-io/cocoindex-code

Killing a stale daemon deletes the live daemon's socket

Open Beginner friendly
#288 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
2.7k
Forks
217
Avg merge
1d 4h
Merged PRs (30d)
4

Description

A daemon unlinks daemon.sock on shutdown without checking whether the node at that path is still its own. So killing a stranded daemon removes the live daemon's socket: that daemon keeps running but is unreachable, and the next client spawns a replacement. kill / pkill cleanup raises the process count instead of lowering it.

S=~/.cocoindex_code/daemon.sock

ccc daemon status                               # a daemon is live (not passive — self-starts)
A=$(cat ~/.cocoindex_code/daemon.pid)
ls -i $S                                        # 179763394  ...daemon.sock   <- A's node

nohup ccc run-daemon >/dev/null 2>&1 & sleep 5
B=$(cat ~/.cocoindex_code/daemon.pid)
ls -i $S                                        # 179763419  ...daemon.sock   <- B unlinked A's node, bound its own

Both daemons still hold a socket, and both report the same path — but they are different objects, and only B's is the one at the path:

$ lsof -p $A -p $B | grep daemon.sock
python3.1 40288 ... 12u unix 0x31379fddf5fa3701 ... /Users/…/daemon.sock   <- A, unlinked
python3.1 40341 ... 14u unix 0x72f981a44d8e296f ... /Users/…/daemon.sock   <- B, at the path

Now SIGTERM the displaced daemon:

kill $A; sleep 2
ls -i $S                                        # No such file or directory — A deleted B's node
kill -0 $B && echo "B alive, no socket"

The shutdown block guards one artifact and not the other (daemon.py, 0.2.32):

if sys.platform != "win32":
    try:
        Path(sock_path).unlink(missing_ok=True)   # unconditional
    except Exception:
        pass
try:
    stored = pid_path.read_text().strip()
    if stored == str(os.getpid()):                # guarded
        pid_path.unlink(missing_ok=True)

The PID file has the "am I still the owner?" test; the socket doesn't. Recording the socket's inode at bind time and unlinking only on a match would close it.

Separate from #243, which serializes client startup but doesn't touch this path.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in daemon.py at the shutdown block for ccc run-daemon and trace where the Unix socket is bound. Reproduce the two-daemon scenario from the issue, then verify that stopping a displaced daemon leaves the live daemon's socket available while its own cleanup still works.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.