You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -38,7 +38,7 @@ Only the entry point needs `@trace`. Everything it calls -- `add()`, imports, cl
38
38
Start an isolated worker (temporary venv with `--tmp`, cleaned up on exit):
39
39
40
40
```bash
41
-
pyfuse worker --tmp --backend shm://localhost:9847 # Same machine using shared memory
41
+
pyfuse worker --tmp --backend local://localhost:9748 # Same machine (async TCP)
42
42
pyfuse worker --tmp --backend redis://localhost:6379 # Remote using Redis
43
43
```
44
44
@@ -84,7 +84,7 @@ Common mappings (`cv2` -> `opencv-python`, `PIL` -> `Pillow`, etc.) are built in
84
84
-**Class methods** -- `self.method()` and `cls.method()` dependencies are detected. Entire class hierarchies (including `super()`), class-level attributes, decorators (`@dataclass`, etc.), and metaclass keywords are reconstructed.
85
85
-**Retry and timeout** -- `@trace(timeout=30, retries=3)` with exponential backoff.
└── local.py # LocalBackend: async-native TCP for same-machine IPC
37
37
```
38
38
39
39
## Architecture overview
@@ -97,7 +97,7 @@ await Worker.run(task)
97
97
-**Class-level attributes**: Class body statements (assignments, annotated assignments, docstrings) are extracted from AST and emitted in reconstructed class blocks. Class decorators (`@dataclass`, etc.) and metaclass keywords (`metaclass=ABCMeta`) are captured and emitted.
-**Decorator stripping**: `@trace` lines are removed from captured source so reconstructed code doesn't depend on pyfuse.
100
-
-**Backend auto-detection**: `connect()` picks Redis or shared memory based on URL scheme. Falls back to `PYFUSE_BACKEND` env var.
100
+
-**Backend auto-detection**: `connect()` picks Redis or local TCP backend based on URL scheme. Falls back to `PYFUSE_BACKEND` env var.
101
101
-**Worker caching**: Keyed by SHA-256 of all reachable content hashes (sorted + joined). Same code from different clients = cache hit.
102
102
-**Async-native I/O**: All backend methods, worker execution, result handling, pip installation, and subprocess management use `asyncio`. Sync user functions run in `loop.run_in_executor()` to avoid blocking the event loop.
103
103
-**Heartbeat**: Workers send heartbeats via `asyncio.create_task`. Client-side stall detection tracks when heartbeat *values* last changed using local monotonic clock (no cross-machine timestamp comparison).
@@ -166,7 +166,7 @@ pytest # run all tests
166
166
pytest tests/test_api.py # specific module
167
167
```
168
168
169
-
15 test modules covering: API surface, AST analysis, async features (Result.result, await, .run(), .start(), .map(), gather, heartbeat, stall detection), auto-discovery (including metaclass keywords, class attributes, class decorators, `__init_subclass__`), dependency management, graph operations, integration scenarios, remote execution, runtime tracing (including closure capture of non-traced functions, lambdas, constructor expressions, pickle fallback), shared memory backend, store operations, stress tests (47 functions across 7 files), task serialization, temp venv management, and worker caching/execution.
169
+
15 test modules covering: API surface, AST analysis, async features (Result.result, await, .run(), .start(), .map(), gather, heartbeat, stall detection), auto-discovery (including metaclass keywords, class attributes, class decorators, `__init_subclass__`), dependency management, graph operations, integration scenarios, local backend (async-native TCP), remote execution, runtime tracing (including closure capture of non-traced functions, lambdas, constructor expressions, pickle fallback), store operations, stress tests (47 functions across 7 files), task serialization, temp venv management, and worker caching/execution.
170
170
171
171
All async tests use `pytest-asyncio` with `asyncio_mode = "auto"`.
Copy file name to clipboardExpand all lines: docs/TECHNICAL_OVERVIEW.md
+5-7Lines changed: 5 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,7 +43,7 @@ pyfuse/
43
43
backends/
44
44
base.py Backend ABC: async pluggable transport interface
45
45
redis.py RedisBackend: redis.asyncio with RPUSH/BLPOP pattern
46
-
shm.py SharedMemoryBackend: same-machine IPC via shared memory
46
+
local.py LocalBackend: async-native TCP for same-machine IPC
47
47
```
48
48
49
49
## Remote execution flow
@@ -107,15 +107,13 @@ Result notifications use Redis Pub/Sub (`PUBLISH`/`SUBSCRIBE`). Batch heartbeat
107
107
108
108
The `redis` package is imported lazily and is an optional dependency.
109
109
110
-
### SharedMemoryBackend
110
+
### LocalBackend
111
111
112
-
Uses `multiprocessing.shared_memory`for zero-copy payload transfer and `multiprocessing.managers.BaseManager` for cross-process coordination. No external services required -- suitable for same-machine worker pools.
112
+
An async-native TCP backend for same-machine IPC. A lightweight broker server built on `asyncio.start_server` handles task dispatch, result routing, and heartbeats -- no threads, no `multiprocessing`, no external services.
The backend auto-detects its role: it tries to connect as a client first; if no server is running, it starts one. Shared memory blocks are tracked and cleaned up on exit via `atexit`.
117
-
118
-
Since `BaseManager` is inherently synchronous, proxy RPC calls are wrapped in `asyncio.to_thread()`. The overhead is negligible for sub-millisecond IPC calls.
116
+
The broker auto-starts as a subprocess on first connection (or can be started explicitly with `server=True`). All I/O is native `asyncio` -- the backend opens TCP connections to the broker and communicates via a length-prefixed JSON protocol. Streaming operations (`listen()`, `subscribe_results()`) use dedicated connections; RPC operations share a single connection protected by an `asyncio.Lock`.
0 commit comments