A lightweight multiprocessing DAG execution engine with message queues and external control options.
Project description
EasyDAG
EasyDAG is a lightweight, multiprocessing-friendly Directed Acyclic Graph (DAG) execution engine for Python.
It lets you define task nodes, declare dependencies, and execute them in parallel — while emitting structured lifecycle events and inter-process messages for logging, progress reporting, or external systems such as web dashboards.
EasyDAG is designed to be simple, explicit, and embeddable, without the operational overhead of workflow schedulers.
Key Features
- ⚙️ Define DAGs using plain Python functions
- ⚡ Parallel execution via
multiprocessing - 🧠 Automatic dependency resolution
- 📬 Multiprocess-safe message queue for side effects
- 🧵 Message handlers run safely in the main process
- 🪝 Lifecycle hooks via a clean interface (ABC)
- 🛑 Cancellation, fail-fast, and timeout support
- 🌐 Optional WebSocket interface for live monitoring & control
- 📦 No external runtime dependencies for the core engine
Installation
pip install easydag
Quick Start
from EasyDAG import EasyDAG, DAGNode
def task_a():
return 2
def task_b(id_a):
return id_a * 10
dag = EasyDAG(processes=4)
dag.add_node(DAGNode("id_a", task_a))
dag.add_node(DAGNode("id_b", task_b))
dag.add_edge("id_a", "id_b")
outputs = dag.run()
print(outputs)
Core Concepts
DAG
A DAG is a set of nodes with directed dependencies. A node may only execute once all of its dependencies have completed successfully.
EasyDAG guarantees:
- No node runs before its dependencies
- Each node runs at most once (unless retried)
- Independent nodes run in parallel
DAGNode
Each node wraps:
- A callable function
- Static positional and keyword arguments
- Retry configuration (optional)
DAGNode(
node_id="A",
func=process_data,
args=(10,),
kwargs={"foo": "bar"},
max_retries=2
)
Dependencies are resolved automatically by matching upstream node IDs to function parameters.
Message Queue System (Side Effects)
EasyDAG includes an optional multiprocessing-safe message queue designed for side effects:
- Logging
- Progress updates
- Metrics
- Database writes
- External notifications
This keeps compute nodes pure and avoids unsafe shared state.
Defining a Queue
from EasyDAG import MultiprocessQueue
queue = MultiprocessQueue()
dag = EasyDAG(processes=4, mp_queue=queue)
Registering Handlers (Main Process)
Handlers always run in the main process, never in workers.
def log_progress(payload):
print("Progress:", payload)
queue.register_message_handler("progress", log_progress)
Sending Messages from Nodes
If a node function includes the reserved message_queue parameter, EasyDAG injects it automatically.
def process_data(x, message_queue=None):
message_queue.put(
QueueMessage("progress", {"value": x})
)
return x * 2
If the parameter is omitted, the queue is not passed.
Lifecycle Interface (Execution Hooks)
EasyDAG exposes a formal interface abstraction via an abstract base class:
from EasyDAG import EasyInterface
This allows you to observe and control execution without coupling logic to the engine.
Supported Hooks
dag_starteddag_finishednode_startednode_progressnode_finishednode_erroredrun()cancel()
You can implement your own interface to:
- Emit events
- Drive UIs
- Collect metrics
- Integrate APIs
Cancellation & Fail-Fast
EasyDAG supports:
- User-initiated cancellation
- Fail-fast execution
- Execution timeouts
Cancellation halts scheduling of new nodes and can be configured to terminate or safely complete in-flight tasks.
Execution outcome is tracked explicitly via DAG status (success, failed, cancelled, timeout).
WebSocket + FastAPI Demo
A full working example is available at:
📁 https://github.com/Mechatronicist/easyDAG-Web
What the demo shows
- Building a DAG
- Emitting node & DAG lifecycle events
- Streaming events over WebSockets
- Starting and cancelling execution from the browser
- Viewing live progress in real time
When to Use EasyDAG
EasyDAG is ideal when you need:
-
A local, Python-native DAG engine
-
Parallel execution with dependencies
-
Fine-grained control over execution
-
Lightweight orchestration without infrastructure
-
A simpler alternative to:
- Airflow
- Prefect
- Ray
- Dask
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 easydag-0.2.3.tar.gz.
File metadata
- Download URL: easydag-0.2.3.tar.gz
- Upload date:
- Size: 18.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62684c472c87c8e52f6b96b4d1faba734f84a729414ee9699a3ec68488a7c9c0
|
|
| MD5 |
95b85ea7b8393ee2deb4e3f2564bc612
|
|
| BLAKE2b-256 |
f2e873f3befc3d26c0a86fb8aa9aa493fd74fa4960d7951da2dcaf9c88bd3faf
|
Provenance
The following attestation bundles were made for easydag-0.2.3.tar.gz:
Publisher:
publish.yml on Mechatronicist/easyDAG
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
easydag-0.2.3.tar.gz -
Subject digest:
62684c472c87c8e52f6b96b4d1faba734f84a729414ee9699a3ec68488a7c9c0 - Sigstore transparency entry: 973059185
- Sigstore integration time:
-
Permalink:
Mechatronicist/easyDAG@d521984fe4caf07cb1f255153e391150cc29ecac -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/Mechatronicist
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d521984fe4caf07cb1f255153e391150cc29ecac -
Trigger Event:
release
-
Statement type:
File details
Details for the file easydag-0.2.3-py3-none-any.whl.
File metadata
- Download URL: easydag-0.2.3-py3-none-any.whl
- Upload date:
- Size: 15.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96a2f19af6a33b7a4156ce3dcf7ea417a071df078136b31932b07db1510b33b4
|
|
| MD5 |
fba8c106ab130fc8a79d98ab5a0b92db
|
|
| BLAKE2b-256 |
17d04975f88f3d30687398d44de43809e2f23aaf01ccc3a2e2f3c1002b2fdbf4
|
Provenance
The following attestation bundles were made for easydag-0.2.3-py3-none-any.whl:
Publisher:
publish.yml on Mechatronicist/easyDAG
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
easydag-0.2.3-py3-none-any.whl -
Subject digest:
96a2f19af6a33b7a4156ce3dcf7ea417a071df078136b31932b07db1510b33b4 - Sigstore transparency entry: 973059245
- Sigstore integration time:
-
Permalink:
Mechatronicist/easyDAG@d521984fe4caf07cb1f255153e391150cc29ecac -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/Mechatronicist
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d521984fe4caf07cb1f255153e391150cc29ecac -
Trigger Event:
release
-
Statement type: