russellromney/honker
GitHub: russellromney/honker
honker是一个SQLite扩展,提供轻量级的通知和任务队列功能。
Stars: 2765 | Forks: 67

honker
`honker` 是一个 SQLite 扩展和语言绑定,它为 SQLite 添加了
Postgres 风格的 `NOTIFY`/`LISTEN` 语义,内置
持久的 pub/sub、任务队列和事件流,无需客户端轮询
或守护进程/代理。任何可以
`SELECT load_extension('honker')` 的语言都获得相同的功能。
`honker` 用单个微秒级的
`PRAGMA data_version` 读取替换了队列表轮询。默认监视器每 1 毫秒
检查一次,提供类似推送的语义和单数毫秒级的跨进程
交付;当较低的空闲 CPU 比最低延迟唤醒更重要时
提高监视器间隔。
如果 SQLite 是您的首选数据存储,队列应位于同一文件中。`INSERT INTO orders` 和 `queue.enqueue(...)` 可以在
同一事务中提交。回滚将删除两者。
有关指南和 API 详细信息,请参阅 [honker.dev](https://honker.dev),以及
[绑定支持](BINDINGS.md) 了解每个绑定支持的内容。
[Simon Willison 突出了 honker](https://simonwillison.net/2026/Apr/24/honker/)
作为 SQLite 的交易性出站模式实现。
## 快速入门
```
pip install honker
```
```
import honker
db = honker.open("app.db")
emails = db.queue("emails")
with db.transaction() as tx:
tx.execute("INSERT INTO orders (user_id) VALUES (?)", [42])
emails.enqueue({"to": "alice@example.com"}, tx=tx)
async for job in emails.claim("worker-1"):
send_email(job.payload)
job.ack()
```
入队与订单插入是原子的。另一个进程中的
当事务提交时,工作员会唤醒。
## 它做什么
- 在一个 SQLite `.db` 文件上跨进程通知/监听
- 可持久至少一次队列,具有重试、延迟作业、优先级、
可见性超时、死信行和任务结果存储
- 可持久流,具有每个消费者的偏移量
- 基于时间的调度,使用 cron 和 `@every
` 表达式
- 命名锁、速率限制和交易性出站助手
- 通过 SQLite 可加载扩展的 SQL 函数
- 轻量级绑定,支持 Python、Node.js、Rust、Go、Ruby、Bun、Elixir、C++、
.NET / C#、Java/JVM 和 Kotlin
故意不包括:工作流 DAG、任务链/组/和弦、多写者复制,
或跨机器的分布式锁定。
## 为什么
SQLite 越来越多地成为已发布项目的数据库。这些项目
最终需要 pub/sub 和任务队列。通常的答案是 "添加 Redis
+ Celery。" 这有效,但它引入了第二个数据存储,它有自己的
备份故事,业务表和队列之间的双写问题,以及一个代理来运行。
Honker 采用的方法是,如果 SQLite 是主要的数据存储,队列应位于同一文件中。队列只是表中的行
具有部分索引。每个绑定都使用相同的模式和解耦器,
因此一种语言可以入队工作,另一种语言可以获取它。
## 设计
Honker 围绕三个部分构建:
- 带有 `notify()` / `listen()` 的短暂 pub/sub
- 带有每个消费者偏移量的持久流
- 带有可见性超时和重试的最少一次队列
所有三个都是您事务内的 INSERT。将 `queue.enqueue(...)`、`stream.publish(...)` 或 `notify(...)` 放在
创建工作的写入旁边。提交将留下两行。回滚将删除两行。
SQLite 没有服务器端推送通道,因此 honker 使用共享监视器。
稳定的后端每毫秒读取 `PRAGMA data_version`;当计数器改变时,
监听器重新读取索引的 SQLite 状态。
如果您使用您应用程序的现有 SQLite 文件,honker 将在
每次提交该文件时唤醒工作员。大多数唤醒将不会找到给定
队列或通道的工作。这种过度触发是有意的:一个索引 SELECT
很便宜,而一个错过唤醒是一个正确性错误。稳定的语义是:
- 在提交更新时唤醒
- 忽略回滚的工作
- 在每次唤醒后重新读取 SQLite 状态
- 使用基于文件的 SQLite 数据库,而不是 `:memory:`
可选的源构建后端也存在,用于内核文件事件和 WAL
共享内存读取。有关哪些绑定公开后端选项以及 CI 证明的内容,请参阅
[绑定支持](BINDINGS.md)。
Honker 是单机文件后端的。SQLite 的锁定模型是为一个主机写入一个数据库文件而设计的;两个服务器通过
NFS 写入相同的 `.db` 不是 Honker 部署策略。
## 先前艺术
[`pg_notify`](https://www.postgresql.org/docs/current/sql-notify.html)
为 Postgres 提供了快速的触发器,但没有重试或可见性超时。
[pg-boss](https://github.com/timgit/pg-boss) 和
[Oban](https://hexdocs.pm/oban/) 是我们在 SQLite 上追求的 Postgres 方面的黄金标准。
[Huey](https://github.com/coleifer/huey) 是一个
一个出色的 SQLite 后备 Python 任务队列。如果您已经运行 Postgres,
使用 Postgres 工具,因为它们很出色。
交易性出站想法也归功于 Brandur Leach 的
[Postgres 中的交易性阶段作业清除](https://brandur.org/job-drain):
在业务行相同的交易中写入作业行,然后让
工作员在提交后交付它。
## 绑定
| 生态系统 | 包 / 路径 | 备注 |
| --- | --- | --- |
| Python | `pip install honker` | 包含 Python API 和可加载扩展的电池包;发布轮盘中包含 |
| Node.js | `npm install @russellthehippo/honker-node` | 原生 Node 绑定 |
| Ruby | `gem install honker` | 可用平台上的预编译原生 gem |
| .NET / C# | `dotnet add package Honker` | 包含捆绑运行时资源的 NuGet 包 |
| Rust | `honker`, `honker-core`, `honker-extension` | 核心引擎和 Rust 包装器 |
| Elixir | Hex 包 `honker` | 解耦器支持的 Elixir 绑定 |
| Go, Bun, C++, JVM, Kotlin | 在 `packages/` 中 | 在树内维护的绑定 |
| SQLite | `honker-extension` | 适用于任何 SQLite 3.9+ 客户端的可加载扩展 |
详细的兼容性表位于 [BINDINGS.md](BINDINGS.md).
语言特定的安装和 API 说明位于每个包的 README 中。
## SQL 扩展
任何可以加载扩展的 SQLite 客户端都可以直接使用 honker:
```
.load ./libhonker_ext
SELECT honker_bootstrap();
INSERT INTO _honker_live (queue, payload) VALUES ('emails', '{"to":"alice"}');
SELECT honker_claim_batch('emails', 'worker-1', 32, 300); -- JSON array
SELECT honker_ack_batch('[1,2,3]', 'worker-1'); -- DELETEs; returns count
SELECT honker_sweep_expired('emails'); -- count moved to dead
SELECT honker_lock_acquire('backup', 'me', 60); -- 1 = got it, 0 = held
SELECT honker_lock_release('backup', 'me'); -- 1 = released
SELECT honker_rate_limit_try('api', 10, 60); -- 1 = under, 0 = at limit
SELECT honker_rate_limit_sweep(3600); -- drop windows >1h old
SELECT honker_cron_next_after('0 3 * * *', unixepoch()); -- 5-field cron
SELECT honker_cron_next_after('*/2 * * * * *', unixepoch()); -- 6-field cron
SELECT honker_cron_next_after('@every 5s', unixepoch()); -- interval schedule
SELECT honker_scheduler_register('nightly', 'backups',
'0 3 * * *', '"go"', 0, NULL); -- periodic task
SELECT honker_scheduler_tick(unixepoch()); -- JSON: fires due
SELECT honker_scheduler_soonest(); -- min next_fire_at
SELECT honker_queue_next_claim_at('emails'); -- next run/reclaim deadline
SELECT honker_stream_publish('orders', 'k', '{"id":42}'); -- returns offset
SELECT honker_stream_read_since('orders', 0, 1000); -- JSON array
SELECT honker_stream_save_offset('worker', 'orders', 42); -- monotonic upsert
SELECT honker_stream_get_offset('worker', 'orders'); -- offset or 0
SELECT honker_result_save(42, '{"ok":true}', 3600); -- save w/ 1h TTL
SELECT honker_result_get(42); -- value or NULL
SELECT honker_result_sweep(); -- prune expired
SELECT notify('orders', '{"id":42}');
SELECT honker_enqueue('emails', '{"to":"alice@example.com"}', NULL, NULL, 0, 3, NULL);
```
该扩展与语言绑定共享表,因此 Python
工作员可以获取由 SQL、Node、Ruby、Go 或任何其他
绑定编写的作业。
## 架构
- 每个 `Database` 一个 `PRAGMA data_version` 监视器;默认
Rust 支持的监视器节奏是 1 毫秒,可以提升
- 计数器变化将唤醒每个监听器/工作员/订阅者
- 订阅者使用索引 SELECT 重新读取 SQLite 状态
- 100 个订阅者仍然共享一个监视器
- 空闲监听器运行零队列/通知 SELECT
队列获取是通过部分索引的一个 `UPDATE ... RETURNING`:
`(queue, priority DESC, run_at, id) WHERE state IN ('pending','processing')`。
确认是一个 `DELETE`。重试耗尽的作业移动到 `_honker_dead`,因此
获取速度取决于挂起/处理作业,而不是旧队列历史。
语言绑定默认使用 WAL,因为它提供了具有一个写者和一个并发读者的并发读取器,
以及高效的 fsync 批处理。其他日志模式仍然有效。正确性和跨进程唤醒不依赖于 WAL;唤醒路径
是 SQLite 自己的 `data_version` 计数器。
## ORMs 和框架
Honker 不提供框架插件。在您的框架或 ORM 连接上加载扩展,运行 `honker_bootstrap()`,
并在 ORM 的交易中调用 SQL 函数。
这适用于 SQLAlchemy、SQLModel、Django、Drizzle、Kysely、sqlx、GORM、ActiveRecord、Ecto、Hibernate、jOOQ、MyBatis、和 Exposed。有关 ORM 指南,请参阅 [honker.dev/guides/orm](https://honker.dev/guides/orm/).
## 性能
在现代笔记本电脑上,honker 可以处理每秒数千条消息。
跨进程唤醒延迟由监视器节奏设置,默认为 1 毫秒。使用以下方法
在您的硬件上测量:
```
python bench/wake_latency_bench.py --samples 500
python bench/real_bench.py --workers 4 --enqueuers 2 --seconds 15
```
## 开发
```
make test # Rust + Python + Node fast path
make test-all # broader suite, including slower tests
make build # build Python package + loadable extension
cargo build --release -p honker-extension
```
仓库布局:
```
honker-core/ # shared Rust engine
honker-extension/ # SQLite loadable extension
packages/ # language bindings
tests/ # cross-package integration tests
bench/ # benchmarks
```
## 文档
- [绑定支持](BINDINGS.md)
- [Python 示例](packages/honker/examples/README.md)
- [基准测试](bench/README.md)
- [路线图](ROADMAP.md)
- [变更日志](CHANGELOG.md)
- [honker.dev](https://honker.dev)
## 许可证
Apache-2.0 OR MIT。请参阅 [LICENSE](LICENSE).标签:DNS解析, MITM代理, PostgreSQL, SQLite, 事件流, 事务, 代码库, 任务调度, 原子操作, 发布订阅, 可视化界面, 延迟任务, 开源项目, 性能优化, 扩展模块, 技术博客, 持久化队列, 数据库, 日志审计, 检测绕过, 死信队列, 消息队列, 社区推荐, 结果存储, 语言绑定, 跨进程通信, 逆向工具, 锁