Skip to main content

EveBus

PyPI Python License: MIT

高性能异步事件引擎 — Rust 匹配核心 + Python 异步 API + HTTP/SSE 接口,可作为远程 RPC 后端。

参考 pyee 风格,扩展通配符匹配、Hook 中间件、Source/Executor/Plugin 实时管理、SSE 流式订阅。

📖 完整使用手册docs/USER_GUIDE.md

安装

pip install pyevebus

带 WebSocket 支持:

pip install pyevebus[ws]

快速开始

import asyncio
from evebus import EventEngine

engine = EventEngine()

@engine.on("data.quotes.*.ETHUSDT")
async def on_quote(topic, event):
    print(f"ETH: {event}")

@engine.once("system.start")
async def on_start(topic, event):
    print("系统启动!")

async def main():
    await engine.emit("system.start", {})
    await engine.emit("data.quotes.BINANCE.ETHUSDT", {"price": 3000})
    await engine.wait_for_complete()

asyncio.run(main())

CLI 工具

EveBus 提供两个独立的 CLI 工具,类似 etcd / etcdctl

命令 定位 说明
evebus 服务端 启动引擎、HTTP API、脚本执行器
evebusctl 客户端 远程管理引擎(源、执行器、插件)

evebus — 服务端

# 启动 HTTP API 服务(生产环境务必启用认证)
EVEBUS_AUTH_TOKEN=my-secret evebus serve --port 8080

# 开发模式(自动重载,不能与 --workers 同时使用)
evebus serve --port 8080 --reload

# 多 Worker(注意:引擎是进程内单例,多 worker 会状态分裂,默认拒绝)
evebus serve --port 8080 --workers 4

# 直接运行脚本执行器
evebus run strategy.py -t "data.*" --auto-reload

⚠️ 安全evebus serve 默认绑定 0.0.0.0 且管理 API 无认证。 生产环境必须设置 EVEBUS_AUTH_TOKEN(见下方安全章节), 否则任何能访问端口的人都能添加执行器 → 远程代码执行。

evebusctl — 客户端管理工具

# 查看引擎状态
evebusctl status

# 发射事件
evebusctl emit "data.test" -d '{"key": "value"}'

# 流式订阅事件(SSE 推送,长连接)
evebusctl subscribe "data.*.ETHUSDT"

# 管理事件源
evebusctl sources list
evebusctl sources add-timer heartbeat --topic system.heartbeat -i 5000
evebusctl sources add-webhook external --prefix external
evebusctl sources start <name>
evebusctl sources stop <name>
evebusctl sources remove <name>

# 管理执行器
evebusctl executors list
evebusctl executors add my_strat -s strategy.py -t "data.*"
evebusctl executors reload <name>
evebusctl executors remove <name>

# 管理插件
evebusctl plugins list
evebusctl plugins remove <name>

所有 evebusctl 命令支持 --url 指定远程服务地址,默认 http://localhost:8080

核心功能

通配符匹配

Rust 实现的 DP 算法,支持 *(任意字符)和 ?(单字符):

@engine.on("data.quotes.*")           # 所有行情
@engine.on("data.quotes.*.ETHUSDT")   # 所有交易所的 ETH
@engine.on("data.*.BTCUSDT")          # 所有数据类型

Hook 系统(中间件)

在事件流的各个阶段注入逻辑:

from evebus import HookStage, HookContext, HookResult

# 验证 + 拦截
async def validate(ctx):
    if not isinstance(ctx.payload, dict):
        return HookResult.INTERCEPTED
    return HookResult.CONTINUE

# 补充数据
async def enrich(ctx):
    ctx.payload["enriched"] = True
    return HookResult.CONTINUE

engine.add_hook(HookStage.PRE_EMIT, validate)
engine.add_hook(HookStage.PRE_EMIT, enrich)
engine.add_hook(HookStage.POST_EMIT, log_hook)

Hook 阶段:

阶段 用途
PRE_EMIT 验证、过滤、修改事件
POST_EMIT 日志、指标、通知
ON_ERROR 错误处理、重试

事件源(Sources)

实时添加/移除事件源:

from evebus import TimerSource, WebhookSource

# 定时器源
timer = TimerSource(name="heartbeat", topic="system.heartbeat", interval_ms=5000)
await engine.add_source(timer)

# Webhook 源
webhook = WebhookSource(name="external", path="/ingest", topic_prefix="external")
await engine.add_source(webhook)

# 停止/移除
await engine.stop_source("heartbeat")
await engine.remove_source("heartbeat")

内置事件源:

说明
TimerSource 定时事件
WebSocketSource WebSocket 数据(自动重连)
WebhookSource HTTP Webhook 注入

执行器(Executors)

动态加载 Python 脚本,运行时重载:

from evebus import ScriptExecutor

executor = ScriptExecutor(
    name="my_strategy",
    script_path="strategies/momentum.py",
    patterns=["data.quotes.*.ETHUSDT"],
    auto_reload=True,
)
await engine.add_executor(executor)

脚本格式:

# strategies/momentum.py
async def on_event(topic: str, payload: dict):
    if payload.get("price", 0) > 3000:
        print("买入信号!")

def on_start():
    print("策略已加载")

插件系统

from evebus import Plugin

class MetricsPlugin(Plugin):
    def __init__(self):
        super().__init__("metrics")
        self.counts = {}

    def on_attach(self):
        @self.on("*")
        async def on_any(topic, event):
            prefix = topic.split(".")[0]
            self.counts[prefix] = self.counts.get(prefix, 0) + 1

await engine.add_plugin(MetricsPlugin())

HTTP API

启动服务后访问:

  • API 文档http://localhost:8080/docs(Swagger UI)
  • 健康检查GET http://localhost:8080/api/v1/health

端点

方法 路径 说明
POST /api/v1/events/emit 发射事件
GET /api/v1/events/subscribe?pattern= 流式订阅事件(SSE)
GET /api/v1/sources 列出所有源
POST /api/v1/sources/timer 添加定时器源
POST /api/v1/sources/webhook 添加 Webhook 源
DELETE /api/v1/sources/{name} 移除源
GET /api/v1/executors 列出所有执行器
POST /api/v1/executors/script 添加脚本执行器
POST /api/v1/executors/{name}/reload 重载脚本
DELETE /api/v1/executors/{name} 移除执行器
GET /api/v1/plugins 列出所有插件
DELETE /api/v1/plugins/{name} 移除插件
GET /api/v1/stats 引擎统计

curl 示例

# 添加定时器
curl -X POST http://localhost:8080/api/v1/sources/timer \
  -H "Content-Type: application/json" \
  -d '{"name": "heartbeat", "topic": "system.heartbeat", "interval_ms": 5000}'

# 发射事件
curl -X POST http://localhost:8080/api/v1/events/emit \
  -H "Content-Type: application/json" \
  -d '{"topic": "data.quotes.BINANCE.ETHUSDT", "payload": {"price": 3000}}'

# 查看状态
curl http://localhost:8080/api/v1/stats

等价于 evebusctl

evebusctl sources add-timer heartbeat --topic system.heartbeat -i 5000
evebusctl emit "data.quotes.BINANCE.ETHUSDT" -d '{"price": 3000}'
evebusctl status

RPC 流式订阅(SSE)

pyevebus 可作为远程 RPC 后端:外部系统通过标准 HTTP/SSE 发射事件和实时订阅事件流

evebusctl 订阅

# 终端 1:订阅(长连接,持续打印事件)
evebusctl subscribe "data.*.ETHUSDT"

# 终端 2:发射事件
evebusctl emit "data.quotes.BINANCE.ETHUSDT" -d '{"price": 3000}'

# 终端 1 输出:
# [1787826311] data.quotes.BINANCE.ETHUSDT {"price": 3000}

Python SDK(RPCClient)

import asyncio
from evebus.rpc import RPCClient

async def main():
    client = RPCClient("http://localhost:8080")

    # 发射事件(单向 RPC)
    await client.emit("data.quotes.BINANCE.ETHUSDT", {"price": 3000})

    # 流式订阅(SSE 推送)
    async for event in client.subscribe("data.*.ETHUSDT"):
        print(event["topic"], event["event"])

asyncio.run(main())

任意语言消费(标准 SSE 协议)

# curl
curl -N "http://localhost:8080/api/v1/events/subscribe?pattern=data.*"
// 浏览器 / Node(EventSource 自动重连)
const es = new EventSource(
  "http://localhost:8080/api/v1/events/subscribe?pattern=data.*.ETHUSDT"
);
es.onmessage = (msg) => console.log(JSON.parse(msg.data));
// Go
resp, _ := http.Get("http://localhost:8080/api/v1/events/subscribe?pattern=data.*")
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
    line := scanner.Text()
    if strings.HasPrefix(line, "data: ") {
        fmt.Println(line[6:])  // 事件 JSON
    }
}

SSE 特性:

  • 每个订阅连接独立队列(背压上限 1024),慢消费者不丢事件
  • 连接断开自动注销 handler(engine.off),无泄漏
  • 支持通配符 pattern(Rust 路由器匹配)
  • 事件格式:data: {"topic": "...", "event": ..., "timestamp": 纳秒}

🔒 安全

认证

管理 API(除 /api/v1/health 外)支持 token 认证。设置环境变量后,所有请求必须携带 X-Auth-Token 头:

EVEBUS_AUTH_TOKEN=my-secret evebus serve --port 8080

# 客户端
curl -H "X-Auth-Token: my-secret" http://localhost:8080/api/v1/stats
evebusctl emit "data.test" -d '{"x": 1}'   # 需要配合 --url 且服务端在受信网络

⚠️ 为什么不默认开启:方便本地开发。生产部署(尤其暴露到公网)必须设置 EVEBUS_AUTH_TOKEN,否则任何人可调用 /api/v1/executors/script 加载任意脚本 → 远程代码执行(RCE)

请求体大小限制

默认限制 1MB,超限返回 413:

EVEBUS_MAX_BODY_BYTES=524288 evebus serve   # 限制 512KB

多 Worker 限制

引擎是进程内单例,多 worker(--workers > 1WEB_CONCURRENCY > 1)会导致订阅/状态分裂。服务端默认拒绝多 worker 启动;如确需横向扩展,请使用独立进程 + 外部存储方案。

其他安全修复(v0.3.1)

  • SSE 订阅背压:队列满时丢弃事件(put_nowait),不阻塞引擎、不泄漏 handler
  • cancel() 后任务回调不再抛 CancelledError
  • SIGTERM 优雅关闭,uvicorn 子进程不残留

架构

┌──────────────────────────────────────────────────────────────────────┐
│                           EveBus                                     │
│                                                                      │
│  ┌──────────┐    ┌──────────────┐    ┌──────────────────────┐        │
│  │ Sources  │──▶ │  Router      │──▶ │  Executors           │        │
│  │          │    │  通配符匹配   │    │  ScriptExecutor      │        │
│  │ Timer    │    │  * ? (Rust)  │    │  Handler (on)        │        │
│  │ WS       │    │              │    │                      │        │
│  │ Webhook  │    │  Hooks       │    └──────────────────────┘        │
│  └──────────┘    └──────────────┘                                    │
│                      ▲                                               │
│                      │ 实时管理                                       │
│        ┌─────────────┴─────────────┐                                 │
│        │  HTTP API + SSE 订阅       │                                │
│        │  FastAPI                  │                                │
│        │  /emit  /subscribe(SSE)   │                                │
│        └───────┬───────────┬───────┘                                │
│                │           │                                         │
│    evebusctl   │           │ 任意语言 (curl/JS/Go)                    │
│    (管理/订阅)  │           │                                         │
│                ▼           ▼                                         │
│        ┌──────────────────────────────┐                              │
│        │  RPCClient SDK (evebus.rpc)  │                              │
│        └──────────────────────────────┘                              │
│                                                                      │
│  ┌─────────────────────────────────────────────┐                     │
│  │  Plugins (metrics/audit/自定义)             │                     │
│  └─────────────────────────────────────────────┘                     │
└──────────────────────────────────────────────────────────────────────┘

Python API

方法 说明
on(pattern, handler) 注册 handler(支持装饰器)
once(pattern, handler) 一次性监听
off(pattern, handler) 移除 handler
emit(topic, event) 发射事件(async)
wait_for_complete() 等待所有 pending 协程
cancel() 取消所有 pending
add_source(source) 添加事件源(async)
remove_source(name) 移除事件源(async)
add_executor(executor) 添加执行器(async)
remove_executor(name) 移除执行器(async)
add_hook(stage, hook) 注册 hook
add_plugin(plugin) 添加插件(async)
stats() 引擎统计

开发

# 环境
uv sync --dev
uv run maturin develop

# 测试 (246 用例,95%+ 覆盖率)
uv run python -m pytest tests/ -v

# 代码检查
uv run ruff check .

License

MIT

Download files

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

Source Distribution

pyevebus-0.3.1.tar.gz (160.5 kB view details)

Uploaded Source

Built Distributions

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

pyevebus-0.3.1-cp39-abi3-win_amd64.whl (174.3 kB view details)

Uploaded CPython 3.9+Windows x86-64

pyevebus-0.3.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (313.3 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

pyevebus-0.3.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (308.4 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

pyevebus-0.3.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (510.4 kB view details)

Uploaded CPython 3.9+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file pyevebus-0.3.1.tar.gz.

File metadata

  • Download URL: pyevebus-0.3.1.tar.gz
  • Upload date:
  • Size: 160.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pyevebus-0.3.1.tar.gz
Algorithm Hash digest
SHA256 f103e8e90c5d5258dbcdd262c955f7f563d0cda3a4b102da57d7c0fd76f7b71d
MD5 cfb115e3b27f37985a2a4226c16bd87f
BLAKE2b-256 a6f874921fe2a45ce4dd5ea3aa69d20dd61f519cb08ce1ff4c435154da26c0e6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyevebus-0.3.1.tar.gz:

Publisher: release.yml on openbot-coder/pyevebus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyevebus-0.3.1-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: pyevebus-0.3.1-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 174.3 kB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pyevebus-0.3.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ded0aa2a95ed85282614a462bcb0d3543d8042ec082fa5cac6cf168f2b1f0eb6
MD5 d6f5ad4382a3b9aa5e25bcb60abcd4e6
BLAKE2b-256 2005f0e358c320b13b3f46014db3bf8e368c3042f6f05e64751ffd5f8d4717a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyevebus-0.3.1-cp39-abi3-win_amd64.whl:

Publisher: release.yml on openbot-coder/pyevebus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyevebus-0.3.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyevebus-0.3.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 897b0de2fa5df157ef38e9f08e96ae9ef5c0d5765a9cb4a6d09f7efe77308bbe
MD5 8a046a7e3c2dbe79f1328cec1e4183fc
BLAKE2b-256 c2c5de245a5135b7e1d4308590aaef5f44eccac26fff6367bc0ce375e4a9ee69

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyevebus-0.3.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on openbot-coder/pyevebus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyevebus-0.3.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyevebus-0.3.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f40954892b99343a0dd39e3e6840b8d6d524e72aa473ef6ec8b761c3dbe34e89
MD5 eb27b84fbbfa36781dac47bd697ac4d1
BLAKE2b-256 aa799c5cf711af2642151401cefb5b97e9c60ae68af22d9b20618109c0f62289

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyevebus-0.3.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on openbot-coder/pyevebus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyevebus-0.3.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for pyevebus-0.3.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 59d659fa4e6bd114f79eab3f199a92f3e13f2fae2c6dd510b3e38744d27e8049
MD5 c02fc83dc3ae121a00dc6a042d627634
BLAKE2b-256 c4859f118168b694fa752ed4a30d151d34c741ac6523cf046eb27297caa4cede

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyevebus-0.3.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: release.yml on openbot-coder/pyevebus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.1 This release

5 files

0.3.0

5 files

0.2.0

6 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page