Skip to main content

Zero-infra background jobs for Python. Runs via daemon threads and piggybacks on your existing database.

Project description

🪶 nano-queue

Zero-infra background jobs for Python. No Redis. No Celery. No extra server costs.

Created by Fidel Chukwunyere

PyPI version License: 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

pip install nano-queue

# If you are using Postgres in production, make sure you have your driver:
pip install psycopg2-binary

🚀 How it Works

  1. You wrap a function with @background_task(queue=q).
  2. When called, it instantly serializes the arguments and saves the job to a nano_tasks table in your DB.
  3. 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


🤝 Contributing

Found a bug? Want to add Redis support? (Just kidding, please don't). Pull requests are welcome!


---

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nano_queue-0.1.1.tar.gz (7.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nano_queue-0.1.1-py3-none-any.whl (6.1 kB view details)

Uploaded Python 3

File details

Details for the file nano_queue-0.1.1.tar.gz.

File metadata

  • Download URL: nano_queue-0.1.1.tar.gz
  • Upload date:
  • Size: 7.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for nano_queue-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d5a3c232c42255ab471fbb3ab5d1cb4fdbac8d4e7b8fe884818a81d884a4493c
MD5 627adb106c0c772941e83300fe8cdc6a
BLAKE2b-256 4a7da189764b86e691c3e61708bee3e506fa32726db7e6964893f790d1572db9

See more details on using hashes here.

File details

Details for the file nano_queue-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: nano_queue-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 6.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for nano_queue-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 77c29d996148628247b06c7692ec61a1bf9387ee419d8ee15dc838c19823e94c
MD5 1b3b8be8905df54e42ceb5affee860c0
BLAKE2b-256 0b16f0beea23738ba99715c9319e7432c4409eb8916699ee5e4f57bbc9ac5c9c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page