Uncategorized

Honker: Postgres NOTIFY/LISTEN for SQLite

Honker, a new SQLite extension that launched on Hacker News today, brings PostgreSQL’s NOTIFY/LISTEN semantics to SQLite databases. The project fills a real gap: SQLite apps have traditionally needed Redis and Celery to handle background jobs and inter-process messaging, introducing operational overhead and dual-write bugs. Honker keeps everything in a single .db file by monitoring SQLite’s Write-Ahead Log as a cross-process commit signal, achieving single-digit millisecond notification delivery without polling.

The WAL File Trick That Makes It Work

Honker’s core innovation replaces database polling with file-change notifications on SQLite’s Write-Ahead Log. A dedicated thread monitors the .db-wal file via stat(2) every 1 millisecond. When the file size or modification time changes—indicating a commit—it fans out wake signals to all subscribers, who then execute indexed SELECT queries.

This achieves push semantics with negligible overhead. stat() calls cost roughly 1 microsecond of CPU time, and idle listeners consume only the stat thread’s resources. The approach is pragmatic: over-triggering is acceptable because indexed queries are cheap, while missed signals would be fatal.

The creator chose stat() over alternatives like inotify or FSEvents for cross-platform reliability. Darwin’s kqueue drops same-process write notifications, breaking the common pattern of listener and enqueuer in the same process. stat() polling works everywhere, consistently. Community members on Hacker News debated using PRAGMA data_version instead, but the file monitoring approach has proven more robust across different concurrency models.

Atomic Commits Solve the Dual-Write Problem

Honker enables atomic transactions where business data and queue operations commit or rollback together. Traditional Redis and Celery architectures create dual-write problems: if the queue operation fails, the business transaction may have already committed, leaving your system in an inconsistent state. Order created, email never sent.

Honker’s transaction pattern eliminates this:

with db.transaction() as tx:
    tx.execute("INSERT INTO orders (user_id) VALUES (?)", [42])
    emails.enqueue({"to": "alice@example.com"}, tx=tx)
    # Both commit together or both rollback

As one Hacker News commenter noted, “atomic commit with the business data is the selling point over separate IPC.” Developers who’ve been bitten by dual-write bugs will immediately understand the value. This reliability guarantee differentiates Honker from external broker architectures.

More Than Just Pub/Sub

Honker isn’t just NOTIFY/LISTEN—it’s a complete messaging toolkit. Durable work queues provide retries with exponential backoff, priority scheduling, delayed jobs, and dead-letter tables for failed tasks. Event streams offer per-consumer offset tracking, enabling CQRS and event sourcing patterns. Cron-style scheduling with leader election handles periodic tasks without external schedulers.

The project supports seven programming languages through SQLite extension bindings: Python, Node.js, Rust, Go, Ruby, Bun, and Elixir. This multi-language approach is significant. Any language with SQLite bindings can access the extension’s SQL functions directly, while high-level bindings provide convenience wrappers. Here’s the Python task decorator pattern:

@emails.task(retries=3, timeout_s=30, name="send_email")
def send_email(to: str, subject: str) -> dict:
    # Send email logic here
    return {"sent_at": time.time()}

# Enqueue and optionally wait for result
result = send_email("alice@example.com", "Hi").get(timeout=10)

Queues use partial indexes on pending and processing states, keeping hot-path scans bounded by active jobs rather than total history. This design choice maintains performance as the dead-letter table grows.

When to Use It (and When to Skip It)

Honker shines for single-server SQLite applications: shipped software, embedded systems, internal tools, or microservices where each service owns its database. SQLite on NVMe can handle thousands of writes per second—enough for the vast majority of web applications.

Skip Honker for multi-server distributed systems. WAL requires shared memory and doesn’t work over network filesystems like NFS. Use Postgres with NOTIFY/LISTEN combined with pg-boss or Oban if you need horizontal scaling. Also avoid Honker for high-volume message throughput in the millions per day; Redis or Kafka handle that workload better.

The project is marked experimental with “API may change” warnings. It has 158 stars on GitHub as of launch day, with 138 commits and active development. Integration tests cover crash recovery and multi-language interop, but this isn’t battle-tested in high-traffic production environments yet.

Thread-based concurrency languages like Go, Java, and C# benefit less from Honker’s cross-process features. In these languages, in-process channels are often simpler for single-writer SQLite architectures. Process-based concurrency languages like Python, JavaScript, and Ruby see more value from cross-process messaging primitives.

How It Stacks Up Against Alternatives

Huey provides SQLite-backed queuing for Python, but only Python. Honker’s extension approach supports seven languages with consistent semantics. Developers working in polyglot environments gain flexibility without maintaining separate queue implementations.

Celery with Redis requires running a separate broker service, adding operational overhead and introducing dual-write scenarios. Honker’s single-file datastore simplifies backups and eliminates the need to coordinate transactions across two systems.

For Postgres users, pg-boss and Oban remain the gold standard. They leverage Postgres’s native NOTIFY/LISTEN and FOR UPDATE SKIP LOCKED features with mature, battle-tested implementations. Use them if Postgres is your primary database or you need proven horizontal scaling.

Redis requires a running server process—daemon monitoring, separate backups, network dependencies. Honker embeds directly into your application with zero configuration. Trade operational simplicity for horizontal scaling capabilities.

Developer Concerns from the Launch

The Hacker News discussion raised legitimate edge cases. One developer asked whether stat() polling handles WAL checkpoint correctly: “When SQLite truncates WAL back to zero, does the stat() polling handle that correctly? Feels like there’s a window where events could get lost.” The project’s documentation hasn’t fully addressed these checkpoint scenarios yet.

This experimental status is important context. Honker represents an innovative approach to SQLite messaging, but it’s not production-proven. Evaluate the tradeoffs carefully: single-file simplicity and atomic commits against maturity and edge-case documentation.

Completing the SQLite Vision

Honker fits into the broader “just use SQLite” movement gaining traction in 2026. Rails 8 positions SQLite as production-ready. Turso and LibSQL enable distributed SQLite with eventual consistency. Litestream provides continuous backup to S3. These tools collectively transform SQLite from an embedded database into a viable backend stack.

Honker completes the picture by adding the messaging layer SQLite lacked. Data, queues, and streams in one file. No separate brokers to maintain. Atomic commits across your entire state. For single-server applications prioritizing operational simplicity, that’s compelling.

The project is experimental, but the approach is sound. WAL file monitoring is clever engineering. Multi-language support via SQLite extensions is the right architecture. If you’re building on SQLite and need background jobs, Honker deserves evaluation.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *