Skip to content

Pub/Sub

Honker’s pub/sub is a direct analog of Postgres’s pg_notify / LISTEN: fire-and-forget signals between processes that share a SQLite file. The Python binding measured 2.9 ms p50 cross-process wake latency on an Apple M1 Pro over 500 samples. No replay, no delivery guarantees. For that, use Streams.

The wire format is the same across bindings: a Python publisher and a Go listener talk to the same channel through the same .db file.

import honker
db = honker.open("app.db")
with db.transaction() as tx:
tx.notify("orders", {"id": 42, "event": "placed"})

The notification commits with the surrounding transaction. If the tx rolls back, no one receives it.

The listener starts from MAX(id) at attach time. Historical notifications are not replayed. Honker runs a shared commit-poll thread at 1 ms cadence (one PRAGMA data_version read per database, counter increments on every commit from any connection in any journal mode), so every listener in the process wakes on any commit and then filters by channel at the SELECT level.

async for notif in db.listen("orders"):
print(notif.channel, notif.payload)

The commit watcher fires on commits from any process. A FastAPI app, a CLI worker, and a cron job can all notify() the same channel, and a separate listener receives every signal within a few milliseconds. No coordination, no broker, no extra network hop.

Notifications accumulate in _honker_notifications until you prune them. There’s no auto-prune because “how much history do you want” is a product decision.

BindingTyped age pruningTyped max-count pruning
Python, Node, Rust, .NET, Java, Kotlinyesyes
Ruby, Elixiryesno
Go, Bun, C++nono

Every binding can use the raw-SQL fallback below.

# Python
db.prune_notifications(older_than_s=3600) # delete rows older than 1 hour
db.prune_notifications(max_keep=10_000) # keep only the most recent 10k
// Node
db.pruneNotifications(3600); // delete rows older than 1 hour
db.pruneNotifications(null, 10000); // keep only the most recent 10k
.NET
db.PruneNotifications(olderThanSeconds: 3600);
db.PruneNotifications(maxKeep: 10_000);
// Java (Kotlin uses the same JVM API or notificationPruneOptions { ... })
db.pruneNotifications(NotificationPruneOptions.builder()
.olderThan(Duration.ofHours(1))
.maxKeep(10_000)
.build());

There are no honker_prune_* SQL functions — pruning is a binding-level helper. From raw SQL, delete against the table directly:

DELETE FROM _honker_notifications WHERE created_at < unixepoch() - 3600;