goletter / hyperf-server
A api server component for hyperf.(based https://github.com/goletter/hyperf-server)
v2.0.8
2026-09-10 18:27 UTC
Requires
- php: >=8.0
- goletter/hyperf-modelfilter: ^1.0
- goletter/hyperf-resource: ^1.0
- goletter/hyperf-sls-log: ^1.0
- goletter/hyperf-traits: ^1.0
- goletter/hyperf-utils: ^1.0
- hyperf/filesystem: ^3.1
- hyperf/flysystem-oss: ^1.4
- hyperf/server: ^3.1
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Hyperf API 服务基础组件:路由、中间件、异步队列封装(含任务链)、模型 Cast 等。
安装
composer require goletter/hyperf-server
功能概览
| 模块 | 说明 |
|---|---|
Router |
扩展 Hyperf Router,提供 apiResource |
| Middleware | CORS、Trace、Locale、幂等、响应格式化、模型绑定等 |
QueueService |
异步队列推送 / 批量 / 任务链 / 按 key 串行,自动透传 trace_id |
| Casts | Encrypted、JsonArrayCast、ResourceUrl 等 |
MakeModuleCommand |
模块脚手架命令 |
队列 QueueService
依赖项目已配置 hyperf/async-queue(可选配合 goletter/hyperf-queue 的毫秒池)。
use Goletter\Server\Service\QueueService; use Hyperf\Context\ApplicationContext; /** @var QueueService $queue */ $queue = ApplicationContext::getContainer()->get(QueueService::class);
推送 / 延迟 / 批量
// 立即推送 $queue->push(new SendNotifyJob($id)); // 延迟推送(delay 单位与驱动一致:default 一般为秒,ms 池为毫秒) $queue->delay(new SendNotifyJob($id), 5); $queue->push(new SendNotifyJob($id), 'ms', 200); // 批量并行入队(可被多个 worker 同时消费) $queue->pushBatch([ new JobA($id), new JobB($id), ]);
当 Context 中存在 trace_id 时,push 会自动包装为 TraceableJob,在 handle() 内恢复链路上下文。
任务链 chain
按顺序执行:上一步成功后才入队下一步;任一步抛异常则中断后续。
$queue->chain([ new CreateOrderJob($dto), new DeductStockJob($dto), new SendNotifyJob($dto), ]); // 步与步之间延迟(default 池:秒) $queue->chain([ new Step1Job($id), new Step2Job($id), ], QueueService::QUEUE_DEFAULT, 2); // ms 池:步间 200ms(需配置 RedisMsDriver) $queue->chain([ new Step1Job($id), new Step2Job($id), ], 'ms', 200);
实现要点:
- 入口只入队一个
ChainJob;当前步在同一次消费中执行,成功后再push剩余链 - 与
pushBatch不同:chain串行,pushBatch并行 ChainJob本身不重试(maxAttempts = 0),避免失败重试导致链被重复推进- 链内 Job 须可序列化(勿放入 Container、闭包、PDO 等)
按 key 串行 pushSerial(陆续入队)
适合任务一个个进来、事先不知道完整列表的场景。同一 key 下 FIFO 串行;不同 key 互不阻塞。
// 用户 A 陆续提交 —— 按提交顺序执行 $queue->pushSerial('user:1001', new ProcessTaskJob($task1)); $queue->pushSerial('user:1001', new ProcessTaskJob($task2)); // 间隔 5 秒;失败最多共执行 3 次(含首次),未耗尽则按 delay 重试同一条 $queue->pushSerial('user:1001', new ProcessTaskJob($task3), 'default', 5, 3); // ms 池:步间 / 重试间隔 200ms $queue->pushSerial('user:1001', new ProcessTaskJob($task4), 'ms', 200, 3); // 用户 B 不受 A 阻塞 $queue->pushSerial('user:1002', new ProcessTaskJob($taskX)); $queue->serialWaitingCount('user:1001');
| API | 何时用 |
|---|---|
chain([...]) |
步骤已知,一次性投递;失败中断后续 |
pushSerial($key, $job, $queue, $delay, $maxAttempts) |
陆续入队;同 key FIFO;失败按 delay 重试 |
pushBatch([...]) |
全部并行,无顺序 |
实现要点:
- 任务写入 Redis List
{queue-serial}:{key}:waiting;列表从空变为 1 时启动 runner(首个立即执行) $delay:成功后到下一条的间隔;失败且未达上限时,也是重试同一条的间隔$maxAttempts:本条最多执行次数(默认1= 失败不重试,直接丢弃并继续下一条)- 重试耗尽后丢弃本条并继续后续,避免堵死同 key
- 外层
SerialJob不依赖 async-queue 重试(避免双调度) - 全局并发:默认最多 32 个
SerialJob同时跑(跨 key);满了会busy_delay后再抢槽,减轻「Too many open files」
php bin/hyperf.php vendor:publish goletter/hyperf-server
config/autoload/queue_serial.php:
return [ 'max_concurrent' => 32, // 0 = 不限制 'busy_delay' => 1, 'slot_lease_seconds' => 600, ];
数据量大时建议同时:调低 async_queue.*.concurrent.limit、提高进程 ulimit -n、日志尽量打 stdout/stderr(避免每条日志抢文件句柄)。
队列是否空闲
$status = $queue->getAsyncQueueCompleted('default'); // ['queue' => 'default', 'completed' => bool, 'working' => int, 'backlog' => int, 'failed' => int]
会统计 waiting、delayed 以及 Redis reserved(官方 info() 不含 reserved)。
路由 apiResource
use Goletter\Server\Router\Router; Router::apiResource('users', App\Controller\UserController::class); // GET/POST /users // GET/PUT|PATCH/DELETE /users/{user}
License
MIT