🪨 firm¶
Pure-Python ports of the Rails 8 "Solid" stack. Keep background jobs and caching in the SQL database you already run — no Redis, no extra broker, no new infrastructure.
| Package | Ports | Replaces |
|---|---|---|
| firm-queue | solid_queue |
Sidekiq / Celery / RQ |
| firm-cache | solid_cache |
Redis / Memcached cache |
| firm-channel | solid_cable |
Redis Pub/Sub (Action Cable) |
| firm-audit | (none — original to firm) | Hand-rolled audit logging |
Inspired by the Rails Solid stack from 37signals.
The four packages are independent — install only what you need — but share a design: your database is the single source of truth, accessed through SQLAlchemy with per-dialect locking.
Why database-backed?¶
- One fewer moving part. If you already run PostgreSQL, MySQL, or SQLite, you already have everything you need. Nothing else to deploy, monitor, or secure.
- Transactional. Enqueue a job in the same transaction as the row it depends on.
- Inspectable. Jobs and cache entries are just rows — query them, back them up, debug them.
Quick taste¶
import firm.queue as bq
bq.configure(database_url="postgresql://localhost/myapp")
@bq.job(queue="mailers")
def send_welcome(user_id: int) -> None:
...
send_welcome.enqueue(42) # enqueue from your app
# $ firm-queue start # run workers + dispatcher
from firm.cache import Cache
cache = Cache(database_url="postgresql://localhost/myapp")
cache.fetch("homepage", lambda: render_homepage())
from firm.channel import Channel
ps = Channel(database_url="postgresql://localhost/myapp")
ps.subscribe("room:42", lambda payload: print(payload))
ps.broadcast("room:42", b'{"msg": "hi"}')
from firm.audit import AuditLog
audit = AuditLog(database_url="postgresql://localhost/myapp")
audit.record("invoice.paid", subject=invoice, actor=user, data={"amount": 4200})
Databases¶
SQLite (default), PostgreSQL, and MySQL/MariaDB are all supported and tested live. See Database backends for drivers, locking semantics, and when to use which.
Where to next¶
- New to it? Start with queue: getting started, cache: getting started, channel: getting started, or audit: getting started.
- Coming from Rails? See Comparison to Rails.
- Contributing? See Testing & contributing.