What 3run Actually Is
3run is a lightweight Python-based runtime and task scheduler that lets you define, queue, and execute scripts or commands with dependency management and retry logic built in. It was designed for people who were tired of writing bash one-liners that break when something goes wrong, or dealing with cron jobs that have no visibility into what failed and why. The core idea is simple: you write Python functions or shell commands, declare their dependencies, and 3run handles the execution order, concurrency limits, and failure recovery. Installing it is straightforward — it's a pip package. You define tasks in a configuration file or directly in Python code, then call the runner. A basic task might look like a function that runs a database migration, and a dependent task might be a report generation script that shouldn't start until the migration finishes. 3run tracks state in a small SQLite database by default, so you can inspect what ran, when, and whether it succeeded or failed. That part is actually useful. The syntax is minimal. You decorate a function or register a command, specify which other tasks it depends on, set a concurrency limit if you're running things in parallel, and fire it off. Here's what a typical entry looks like in practice:
You define a task with a decorator or a registration call, list its dependencies as a tuple or list, and optionally set parameters like timeout, max retries, and retry delay. The scheduler then resolves the dependency graph, executes tasks in topological order, and logs everything to that SQLite backend. If a task fails, it retries according to your settings before marking it as permanently failed. You can also inspect the queue state at any time through the CLI or a small web dashboard if you enable that.
How It Works in Real Life
The dependency resolution is where 3run actually saves you time. Instead of writing a Makefile or a long shell script with nested conditionals, you declare what each task needs and let the engine figure out the order. This matters when you have chains like: extract data, transform it, validate the output, load it into the target system, and then send a notification. If the validation step fails, 3run won't run the load step. That's the whole point. Concurrency is handled through a worker pool. You set how many tasks can run simultaneously, and 3run manages the scheduling. This is useful when you have independent tasks that can run in parallel, like processing multiple files or querying several endpoints. The tradeoff is that shared resources like databases need to be handled carefully, which brings me to a specific problem I ran into. I had a pipeline where three tasks all needed to write to the same SQLite database file during a data import. 3run tried to run them in parallel because there were no declared dependencies between them, and I got database lock errors constantly. The fix was ugly but effective: I wrapped the database writes in a context manager that acquired a file-level lock using the fcntl module on Linux, then added a small retry loop with exponential backoff specifically for those write operations. It's not elegant, but it works. A cleaner approach would be to use a proper PostgreSQL instance for the pipeline data instead of SQLite, but that's a infrastructure decision, not a 3run limitation.
Get the Full Details

Known Limitations
The biggest issue with 3run is that it's not designed for long-running services. It's a task runner, not a process manager. If you need something to stay up forever and handle incoming requests, this is the wrong tool. It also doesn't integrate well with Kubernetes or container orchestration platforms out of the box. You'd need to write your own adapter or wrapper for that. The documentation is sparse, which means you'll spend time reading source code to understand edge cases. Another thing people don't realize: 3run's state management assumes you're running it on a single machine. If you try to cluster multiple instances, you'll run into race conditions on the SQLite database unless you switch to a shared backend like PostgreSQL. The project supports this, but it's not the default setup, and you won't find it in the quickstart guide.
When to Use It and When Not To
Use 3run for ETL pipelines, scheduled data processing jobs, deployment scripts that need ordering and retry logic, or any situation where you have a directed acyclic graph of tasks and you're currently managing the orchestration with shell scripts. It cuts the setup time from probably an hour of writing and debugging custom scripts down to maybe fifteen minutes of actual work, depending on how complex your dependency graph is. Don't use it for real-time processing, high-throughput message queues, or anything that requires horizontal scaling across multiple machines without additional infrastructure. In those cases, look at Celery, Airflow, or Prefect instead. They have steeper learning curves and more moving parts, but they solve problems that 3run isn't built for. The download and setup are on PyPI. You can install it with pip install 3run, then check the GitHub repository for examples and the full configuration reference. The README is adequate but not comprehensive — you'll likely end up looking at the source code and test cases to understand the less common features. That's normal for a tool in this space.