An asynchronous, non-polling data hub for Python processes using FastAPI and requests for variable synchronization.
Project description
🌹 rosetrap: The Asynchronous Variable Data Hub
rosetrap provides an efficient, non-polling mechanism for inter-process communication (IPC) and variable synchronization across Python scripts, leveraging FastAPI on the server and the requests library on the client.
It implements a robust, event-driven pattern that allows a consuming process to block indefinitely without consuming CPU cycles until a producing process updates the required variable.
✨ Key Features
- Asynchronous Blocking: Uses
asyncio.Eventon the FastAPI server to suspend client requests, eliminating busy-waiting and high CPU load typically associated with polling. - Zero-Config IPC: No need for complex message queues (Redis, Kafka); state is managed centrally by the lightweight
DATA_HUB. - Deadlock Prevention: Robust client logic handles race conditions where data arrives between the initial status check and the blocking request.
- Simple API: Client-side functions are reduced to two clear commands:
printToServer()(Write) andreceiveFromServer()(Read/Block). - Independent Variables: State management is fully independent for each variable name, allowing concurrent, synchronized access by multiple clients.
🛠️ Installation & Setup
-
Install dependencies:
pip install fastapi requests pydantic uvicorn
-
Start the Server: The
server_data_hub.pyscript must be running first.python server_data_hub.py # Server runs on http://0.0.0.0:8000
🚀 Usage Example: Concurrent Hand-off
This example demonstrates how Client A blocks waiting for Client C's data, and then how Client B blocks waiting for Client A's computed result, all without polling.
1. The Server and Core Utilities
Ensure server_data_hub.py and core_utils.py are in your project directory.
2. Client Scripts
Create these three files in the same directory:
client_A.py (Consumer of X, Producer of Y)
import time
from core_utils import receiveFromServer, printToServer, set_client_id
set_client_id("CLIENT A")
# 1. Block until 'X_Data' is ready
print("CLIENT A: Waiting to receive X_Data...")
x_data = receiveFromServer("X_Data", timeout_seconds=60)
if x_data:
print(f"CLIENT A: Successfully received X_Data: {x_data}")
# 2. Compute a new value 'Y_Data'
time.sleep(1) # Simulate computation time
y_data = str(int(x_data) * 2)
print(f"CLIENT A: Calculated Y_Data = X_Data * 2 = {y_data}")
# 3. Send the new value 'Y_Data'
print("CLIENT A: Sending Y_Data...")
printToServer("Y_Data", y_data)
print("CLIENT A: Finished sending Y_Data.")
else:
print("CLIENT A: Failed to receive X_Data.")
client_B.py (Final Consumer of Y)
from core_utils import receiveFromServer, set_client_id
set_client_id("CLIENT B")
# 1. Block until 'Y_Data' is ready
print("CLIENT B: Waiting to receive Y_Data...")
y_data = receiveFromServer("Y_Data", timeout_seconds=60)
if y_data:
print(f"CLIENT B: Successfully received Y_Data: {y_data}")
print("CLIENT B: Final result received. Execution complete.")
else:
print("CLIENT B: Failed to receive Y_Data. Timeout or error occurred.")
client_C.py (Initial Producer of X)
import time
from core_utils import printToServer, set_client_id
set_client_id("CLIENT C")
# 1. Compute the initial value
initial_value = 50
time.sleep(4) # Simulate initial computation delay
# 2. Send the value 'X_Data'
print(f"CLIENT C: Computation finished. Sending X_Data: {initial_value}")
printToServer("X_Data", initial_value)
print("CLIENT C: Finished sending X_Data.")
3. Execution Sequence
The terminal output will clearly show the blocking and release mechanism.
-
Start Blocking Clients:
python client_A.py & python client_B.py &
Client A and B will print their "Waiting" messages and then immediately stop consuming CPU, as they are blocked on the server's
asyncio.Event.wait(). -
Trigger the Chain:
python client_C.py
Expected Flow:
- Client C sends "50" for
X_Dataafter a 4-second delay. - The Server sees the
X_Datalookout is True (set by Client A) and signals the event. - Client A unblocks, receives "50", computes the result (100), and sends "100" for
Y_Data. - The Server sees the
Y_Datalookout is True (set by Client B) and signals the event. - Client B unblocks, receives "100", and finishes.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rosetrap-0.1.1.tar.gz.
File metadata
- Download URL: rosetrap-0.1.1.tar.gz
- Upload date:
- Size: 7.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fcab437494bde4a2dc290181b5203af95dfb0c9a8a2de0de18b6d2e7fe8b84c6
|
|
| MD5 |
aaf40e53cbe4fd6b54cb59fdee41d0f4
|
|
| BLAKE2b-256 |
92d6d56fa7ad6963ade6de689c66fc94644af3a220e615f03cfd0c483b3f19e2
|
File details
Details for the file rosetrap-0.1.1-py3-none-any.whl.
File metadata
- Download URL: rosetrap-0.1.1-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64febc0a9a9f2146e5c158755eeff79cf1517ab03b8410e30d0bb48d708de1e5
|
|
| MD5 |
83196e53b599161b4bc143f7fc90854c
|
|
| BLAKE2b-256 |
974c2f27a9e5871ba011a3e84959c90feb3ac1370fb2b616e7cd09dc3cefa729
|