hongxunpan/simple-event 是面向 hongxunpan/simple-framework 的事件 Module。
它提供:
- 同步监听器;
- 可选的 Redis Streams 异步监听器;
- 严格 Event 快照和持久化协议;
- best-effort 监听器;
- Worker、失败摘要与监听器白名单;
- framework 应用生命周期适配;
- Module 启用后加载的
event()。
同步模式不依赖 Redis。只有选择 RedisStreamDriver 时才需要安装并启用
hongxunpan/simple-redis。
composer require hongxunpan/simple-event
php bin/simple module:enable eventComposer 只负责安装包。event()、Provider 和生命周期适配只有在 Event Module 启用后才进入
应用运行时。
Event 表达已经发生的业务事实快照:
<?php
namespace App\Events;
use DateTimeImmutable;
use HongXunPan\SimpleEvent\Event;
final readonly class SampleOccurred implements Event
{
public const int VERSION = 1;
public function __construct(
public int $sampleId,
public int $userId,
public DateTimeImmutable $occurredAt,
) {
}
}约束:
- Event 必须是
final readonly; - 构造参数必须与公开实例属性一一对应;
- 未声明
VERSION时默认为1; - 快照字段只允许标量、
null、BackedEnum和DateTimeImmutable; - 不允许携带 ORM Model、Request、Service、数组或任意对象。
同步监听器:
<?php
namespace App\Listeners;
use App\Events\SampleOccurred;
final class WriteSampleAuditLog
{
public function handle(SampleOccurred $event): void
{
// 写入示例审计事实。
}
}异步监听器实现 ShouldQueue:
<?php
namespace App\Listeners;
use App\Events\SampleOccurred;
use HongXunPan\SimpleEvent\Listener\ShouldQueue;
final class SendSampleNotification implements ShouldQueue
{
public function handle(SampleOccurred $event): void
{
// 异步副作用必须按业务唯一事实保证幂等。
}
}监听器的 handle() 必须:
- 是公开实例方法;
- 只接收一个参数;
- 参数类型精确等于配置中的 Event;
- 显式返回
void。
项目 config/events.php:
<?php
use App\Events\SampleOccurred;
use App\Listeners\WriteSampleAuditLog;
return [
'listeners' => [
SampleOccurred::class => [
WriteSampleAuditLog::class,
],
],
];触发:
event(new SampleOccurred(
sampleId: 1,
userId: 10001,
occurredAt: new DateTimeImmutable(),
));同步监听器按配置顺序执行。普通同步监听器异常会原样向上传播,并停止后续监听器。
明确允许失败且不应污染调用链的监听器可以实现:
use HongXunPan\SimpleEvent\Listener\ShouldHandleBestEffort;
final class OptionalListener implements ShouldHandleBestEffort
{
public function handle(SampleOccurred $event): void
{
}
}best-effort 异常会交给 ListenerFailureReporter,但不会阻断后续监听器。
项目可以通过 Provider 覆盖该契约。
安装并启用 Redis Module:
composer require hongxunpan/simple-redis
php bin/simple module:enable redis
php bin/simple module:enable eventconfig/redis.php 只保存连接配置:
return [
'connections' => [
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'port' => (int) env('REDIS_PORT', 6379),
'database' => 0,
'prefix' => 'app:',
],
],
];config/events.php 保存 Event Driver 配置:
<?php
use App\Events\SampleOccurred;
use App\Listeners\SendSampleNotification;
use HongXunPan\SimpleEvent\Driver\Redis\RedisStreamDriver;
return [
'listeners' => [
SampleOccurred::class => [
SendSampleNotification::class,
],
],
'driver' => [
'class' => RedisStreamDriver::class,
'options' => [
'connection' => 'default',
'stream' => 'business-events',
'group' => 'application',
'failed_stream' => 'business-events-failed',
'block_ms' => 5000,
'batch_size' => 10,
'claim_idle_ms' => 60000,
'failed_max_length' => 10000,
],
],
];Redis host、认证、TLS、database 和 prefix 属于 Redis Module;stream、group、批次、 pending 回收和 failed stream 属于 Event Driver。两个配置边界不能混用。
RedisStreamDriver 不读取或编辑 module.enable,只校验 Redis 公开类型、容器绑定与所选
命名连接。通常由已启用的 Redis Module 提供这些运行时能力;项目若替换 Redis Provider,
也必须完整提供相同公开绑定。
单轮消费:
$processed = app(
HongXunPan\SimpleEvent\Worker\EventWorker::class,
)->runOnce();持续运行:
app(HongXunPan\SimpleEvent\Worker\EventWorker::class)->run(
static fn (): bool => $shouldStop,
);信号处理、命令退出码和 Supervisor/systemd 配置由项目负责。
Redis Streams 使用 at-least-once 语义:
- ACK 前退出时整条事件消息可能重新执行;
- 所有异步监听器必须幂等;
- 普通异步监听器失败后,整条消息写入 failed stream;
- XACK 成功后,XDEL 失败只留下可清理残留,不重新执行消息;
- 消息内监听器必须是当前 Event 已登记异步监听器的子集。
项目 Provider 可以覆盖:
EventConfigLoaderTraceIdProviderListenerFailureReporterSerializerDriver
默认 Loader 只读取 config/events.php。若项目不希望使用 events 作为配置名称,应覆盖
EventConfigLoader,不要在包内增加旧键兼容或项目专用回退。
Event Module 会把 framework 的:
RequestHandledSnapshotExceptionOccurredSnapshot
转换为 Event Module 自己的生命周期事件。framework core 不引用 simple-event,也不会直接调用
event()。
composer test共享工作区使用:
SIMPLE_EVENT_AUTOLOAD=/项目/vendor/autoload.php php tests/TestRunner.php当前开发线要求 PHP ^8.5。