Skip to main content

Stdlib-only local IPC — Unix sockets, FIFOs, JSON-line protocol.

Project description

   ┌─────────────────┐      ╔═════════════════╗
   │  codechu — ipc  │═════>║   your daemon   ║
   │  client         │ JSON ║   handler(req)  ║
   │  request()      │<═════║   → response    ║
   └─────────────────┘ line ╚═════════════════╝
        unix socket  ·  fifo  ·  json-line  ·  pidfile

Local IPC the boring way — Unix sockets, FIFOs, one JSON object per line.

codechu-ipc

Stdlib-only local IPC for Linux daemons and sidecars: Unix domain sockets, named pipes (FIFOs), JSON-line framing, server lifecycle helpers. No third-party dependencies. Python 3.10+.

Linux is the primary target; BSD/macOS are best-effort (anything POSIX-y with AF_UNIX and mkfifo should work).

Install

pip install codechu-ipc

API at a glance

from codechu_ipc import UnixServer, UnixClient, FifoChannel, pidfile

# --- Server side ------------------------------------------------------
def handler(req: dict) -> dict:
    return {"echo": req}

with UnixServer("/run/codechu/myapp/control.sock", handler):
    ...  # serve until the context exits

# --- Client side ------------------------------------------------------
client = UnixClient("/run/codechu/myapp/control.sock")
response = client.request({"cmd": "status"})       # → {"echo": ...}
client.notify({"cmd": "shutdown"})                  # fire-and-forget

# --- FIFO -------------------------------------------------------------
ch = FifoChannel("/run/codechu/myapp/events.fifo")
ch.send({"event": "rescan-done"})                   # non-blocking
msg = ch.recv()                                     # blocks for next

# --- Lifecycle --------------------------------------------------------
with pidfile("/run/codechu/myapp/daemon.pid"):
    serve_forever()

Why JSON-line?

  • One object per line. Trivial to parse from any language, any shell pipeline, any log viewer.
  • No length prefixes, no schemas. Easy to inspect with nc -U or socat while debugging.
  • Backpressure is the OS's problem. The kernel's socket buffers do the queuing; this library stays a thin wrapper.

If you need binary framing, multiplexing, or RPC semantics, you want gRPC, not this.

UnixServer(path, handler, *, mode=0o600, backlog=16)

  • Background accept-loop thread; one worker thread per connection.
  • Default socket permissions: owner-only (0o600). Override with mode=.
  • Auto-cleans stale socket files from a crashed previous run; refuses to overwrite a live socket (raises FileExistsError).
  • Handler returning None means "this was a notification, send no response". Anything else is encoded back as one JSON line.
  • Handler exceptions are caught and returned to the client as {"error": "...", "type": "..."} — the server keeps serving.
  • Context manager: with UnixServer(...) as srv: ... calls start()/stop() for you.

UnixClient(path, *, timeout=5.0, retries=3, retry_backoff=0.5)

  • request(payload) — send a JSON line, read one back.
  • notify(payload) — send a JSON line, close. No response read.
  • Retries on ConnectionRefusedError / FileNotFoundError, with exponential backoff (0.5s, 1.0s, 2.0s, ...). Useful for the short window between "daemon is starting" and "daemon is ready".

JsonLineProtocol

The framing helper, exposed so you can build your own transport on top of it.

data = JsonLineProtocol.encode({"hello": "world"})  # → b'{"hello":"world"}\n'

with open("/var/log/myapp.jsonl", "rb") as f:
    for obj in JsonLineProtocol.decode_stream(f):
        print(obj)

FifoChannel(path, *, mode=0o600)

  • Auto-creates the FIFO with mkfifo if missing.
  • send() opens write-side non-blocking — raises BrokenPipeError if no reader is attached, so you don't deadlock.
  • recv() opens read-side blocking and yields one decoded message.
  • FIFOs are unidirectional; for request/response use UnixServer.

pidfile(path)

Context manager that:

  1. Creates the parent directory.
  2. Opens the pidfile and acquires an exclusive flock.
  3. If another process holds the lock, raises BlockingIOError immediately — perfect for "don't start twice" guards.
  4. Writes the current PID, releases the lock, removes the file on exit (including exceptions).
try:
    with pidfile("/run/codechu/myapp/daemon.pid"):
        run()
except BlockingIOError:
    sys.exit("already running")

Design

  • Pure stdlib. socket, threading, fcntl, os, json — no more. The whole library is five small modules.
  • Linux-first. AF_UNIX, mkfifo, flock — all POSIX, but Linux is the platform we run CI on. BSD/macOS work in practice.
  • No magic. No global registry, no event loop, no decorators. You start the server, you stop the server.
  • Crash-safe. Stale socket files are detected on startup; pidfiles are removed on exit; handler exceptions don't kill the server.

Tests

pip install -e ".[dev]"
pytest -q
ruff check src tests

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

codechu_ipc-0.1.0.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

codechu_ipc-0.1.0-py3-none-any.whl (12.0 kB view details)

Uploaded Python 3

File details

Details for the file codechu_ipc-0.1.0.tar.gz.

File metadata

  • Download URL: codechu_ipc-0.1.0.tar.gz
  • Upload date:
  • Size: 14.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for codechu_ipc-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d096574ad8bd4e7aa7f94bb0da730469dce1fceea9d723b798a75aac90f7aafb
MD5 577d1de97a8dcc1e6f3e6b700dcd82bd
BLAKE2b-256 52bd91755225e5eb117af87561056a74c6e6d972bdfafbbce7510f7f46602b0a

See more details on using hashes here.

Provenance

The following attestation bundles were made for codechu_ipc-0.1.0.tar.gz:

Publisher: release.yml on codechu/ipc-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file codechu_ipc-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: codechu_ipc-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for codechu_ipc-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 51bf24965f44ece25ea3a3498754e6b7baaf5bfb1918f702fcfb1448677894bd
MD5 3e242499753bc00d3330ff3412f15925
BLAKE2b-256 7463c079bdf6380fdaff77c355caa6b953249e5cc264a072536cf64fc1215aeb

See more details on using hashes here.

Provenance

The following attestation bundles were made for codechu_ipc-0.1.0-py3-none-any.whl:

Publisher: release.yml on codechu/ipc-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page