Zero-infra background jobs for Python. Runs via daemon threads and piggybacks on your existing database.
Project description
Here is the updated project with the name changed to nano-queue. All references—including package names, class names, file paths, and SQL table names—have been adjusted to reflect the new identity.
README.md
# 🪶 nano-queue
**Zero-infra background jobs for Python. No Redis. No Celery. No extra server costs.**
Created by **[Fidel Chukwunyere](https://github.com/Fidel-c)**
[](https://badge.fury.io/py/nano-queue)
[](https://opensource.org/licenses/MIT)
You just want to send a welcome email or generate a PDF in the background. But suddenly, you are installing Celery, configuring a Redis cluster, and paying for an extra "Worker" dyno on Render or Heroku.
`nano-queue` fixes this.
It is a plug-and-play background task queue that **piggybacks on your existing database** (Postgres/SQLite) and runs silently in a **background daemon thread** inside your main web server process (FastAPI/Django/Flask).
Stop paying for extra infrastructure just to send an email.
---
## 🥊 nano-queue vs. FastAPI BackgroundTasks
*Wait, doesn't FastAPI already have `BackgroundTasks`?* Yes, but it is a massive footgun for production apps. FastAPI's built-in tasks live entirely in RAM and are bound to the specific worker that received the request. `nano-queue` transforms that fragile setup into a **durable message broker**.
| Feature | FastAPI `BackgroundTasks` | `nano-queue` |
| :--- | :--- | :--- |
| **Server Restart / Crash** | ❌ All pending jobs are permanently lost | ✅ Jobs safely persist in your DB |
| **Load Balancing**| ❌ CPU spikes on a single Gunicorn worker | ✅ Idle workers automatically grab jobs |
| **Failure Observability** | ❌ Silent terminal errors | ✅ Tracebacks saved to DB for easy retry |
| **Infrastructure Required** | ✅ None | ✅ None (Piggybacks existing DB) |
---
## ✨ Features
* **Zero Extra Infra:** Uses the database you already have.
* **PaaS Friendly:** Perfect for Render, Heroku, and Railway single-instance deployments.
* **Atomic Locks:** Safe for multi-worker environments (e.g., 4 Gunicorn workers? You get a 4-thread queue automatically without double-processing).
* **Framework Agnostic:** Works beautifully with FastAPI, Django, Flask, or pure Python scripts.
---
## 📦 Installation
```bash
pip install nano-queue
# If you are using Postgres in production, make sure you have your driver:
pip install psycopg2-binary
🚀 How it Works
- You wrap a function with
@background_task(queue=q). - When called, it instantly serializes the arguments and saves the job to a
nano_taskstable in your DB. - A background daemon thread safely polls the DB, atomically claims the job, and executes it without blocking your web requests.
⚡ FastAPI Integration
Integrating with FastAPI is effortless. We recommend using an environment variable (DATABASE_URL) so it runs on SQLite locally, but seamlessly connects to your production Postgres on Render/Heroku.
# main.py
import os
import time
from fastapi import FastAPI
from nano_queue import NanoQueue, background_task
# 1. Initialize the queue (Defaults to local SQLite if no ENV var is found)
db_url = os.getenv("DATABASE_URL", "sqlite:///local_tasks.db")
q = NanoQueue(db_url)
app = FastAPI()
# 2. Decorate your heavy functions
@background_task(queue=q)
def send_welcome_email(user_email: str):
print(f"Connecting to SMTP... sending email to {user_email}")
time.sleep(3) # Simulate heavy I/O
print("Email sent!")
# 3. Call them normally in your endpoints
@app.post("/signup")
def signup(email: str):
# This returns instantly. The email sends in the background.
send_welcome_email(email)
return {"message": "Account created! Check your email."}
🎸 Django Integration
For Django, you want to ensure the queue is initialized when your app starts, but avoid running the worker thread during management commands like makemigrations.
1. Define your tasks (myapp/tasks.py)
import os
import time
from nano_queue import NanoQueue, background_task
from django.conf import settings
# Grab the DB URL from your environment (standard for PaaS deployments)
db_url = os.environ.get("DATABASE_URL", "sqlite:///db.sqlite3")
# Initialize the queue
q = NanoQueue(db_url)
@background_task(queue=q)
def process_payment_webhook(payload: dict):
print("Processing webhook payload...")
time.sleep(5) # Simulate external API call
print(f"Webhook {payload.get('id')} processed safely!")
2. Safely start it in your AppConfig (myapp/apps.py)
import sys
from django.apps import AppConfig
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'
def ready(self):
# Only import and start the queue if we are actually running the server
# This prevents the daemon from starting during `python manage.py collectstatic`
if 'runserver' in sys.argv or 'gunicorn' in sys.argv[0]:
import myapp.tasks
3. Call it in your views (myapp/views.py)
from django.http import JsonResponse
from .tasks import process_payment_webhook
def stripe_webhook(request):
payload = {"id": "evt_12345", "amount": 5000}
# Enqueues to DB instantly and returns 200 OK to Stripe
process_payment_webhook(payload)
return JsonResponse({"status": "received"})
🛠️ Production Tips (Render / Heroku)
If you are deploying to a PaaS like Render, you do not need a background worker dyno.
Simply deploy your web service as usual (e.g., gunicorn app.main:app). Because nano-queue uses a Daemon Thread, it will boot up alongside your web server.
If you scale your web service to 3 instances, you will automatically have 3 background threads processing jobs. The UPDATE ... RETURNING SQL logic ensures that no two instances will ever process the same job twice.
👤 Author
- Fidel Chukwunyere — Creator of nano-queue
🤝 Contributing
Found a bug? Want to add Redis support? (Just kidding, please don't). Pull requests are welcome!
---
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 nano_queue-0.1.0.tar.gz.
File metadata
- Download URL: nano_queue-0.1.0.tar.gz
- Upload date:
- Size: 7.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cbb02f2d2173350f82b06c5e0c7c04207027d3aca49fe05a418b370d7e62aa9c
|
|
| MD5 |
0939c05c50d242aa50245d028ad4f043
|
|
| BLAKE2b-256 |
4a674a42319ae5a98b9d9cf200cb87359ad882bb0faf9812e7e469ee5adb1310
|
File details
Details for the file nano_queue-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nano_queue-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48b80784e33b8ccb55e437fec7cf02bfb620a771a56a9cd6cc766b39b4886679
|
|
| MD5 |
ba8bc3f4d60d6201c47ff722cd0f3fab
|
|
| BLAKE2b-256 |
6ea9d1d529a0210b87049cde743438a65a4be7452f1a96a51c0d4c235ec6fd77
|