新闻详情

新闻详情

首页 / 资讯中心 / 详情

Coolify 中的 Laravel Actions 实践:用 lorisleiva/laravel-actions 构建可复用、可测试的多入口点操作

发布时间:2026/9/7 14:35:04来源:尧图网络
Coolify 中的 Laravel Actions 实践:用 lorisleiva/laravel-actions 构建可复用、可测试的多入口点操作
Coolify 中的 Laravel Actions 实践用 lorisleiva/laravel-actions 构建可复用、可测试的多入口点操作【免费下载链接】coolifyAn open-source, self-hostable PaaS alternative to Vercel, Heroku Netlify that lets you easily deploy static sites, databases, full-stack applications and 280 one-click services on your own servers.项目地址: https://gitcode.com/GitHub_Trending/co/coolifyCoolify 后端基于 Laravel其app/Actions目录下的全部操作类统一采用lorisleiva/laravel-actions包composer.json中锁定^2.10.2来实现。仓库内的技能文档 SKILL.md 系统化地记录了这套模式一个 Action 类只实现一次handle(...)核心业务逻辑却可以通过AsActiontrait 同时作为对象、Controller、Job、Listener、Command 五种入口点运行并能用fake()/mock()/spy()等手段做第一类测试隔离。读完本文你可以掌握 Coolify 中 Action 的完整骨架、五种入口点的接线方式、队列生命周期钩子的真实用法以及一套“业务正确性 入口点接线”双层测试策略。何时把一段逻辑写成 Action技能文档给出的决策规则很明确见 SKILL.md 的 “When to Use an Action”用 Action同一用例需要多个入口点HTTP、队列、事件、CLI或需要一等的编排/fake 能力用普通 Service 类逻辑是局部的、单入口点的、且不太可能以 Action 形式复用。从app/Actions的实际组织看Coolify 遵循了“按领域分子命名空间”的约定App\Actions\Database、App\Actions\Service、App\Actions\Server、App\Actions\Proxy、App\Actions\Application等 13 个子目录共 60 余个 Action 类命名统一为描述性的VerbNoun如StartDatabase、DeployServiceApplication、CleanupDocker。文档同时约定业务/领域逻辑只放在handle(...)中传输层与框架关注点HTTP 响应、CLI IO、队列细节放在适配方法asController、asJob、asListener、asCommand中所有 Action 方法优先显式参数与返回类型复杂数据结构契约优先用 PHPDoc 而非行内注释。基础骨架与对象入口点技能文档给出的最小骨架是?php namespace App\Actions; use Lorisleiva\Actions\Concerns\AsAction; class PublishArticle { use AsAction; public function handle(int $articleId): bool { return true; } }对象入口点有三种等价调用方式详见 references/object.mdPublishArticle::run($id); // 首选静态 helper PublishArticle::make()-handle($id); // 显式 make handle app(PublishArticle::class)-handle($id); // 容器注入配合构造函数 DItrait 还额外提供了条件执行PublishArticle::runIf($condition, ...)与PublishArticle::runUnless($condition, ...)分别在条件成立/不成立时才执行handle(...)。Coolify 源码中大量使用::run()同步编排例如 RestartDatabase 内部直接return StartDatabase::run($database);体现了“Action 编排 Action”的组合风格。一个真实例子是 StartDatabase它接收八种独立数据库模型的联合类型在handle(...)中先检查服务器可用性然后按getMorphClass()分发到StartPostgresql::run()、StartRedis::run()等具体 Action若数据库开启了公网访问还会StartDatabaseProxy::dispatch($database)异步派发代理启动。注意这个文件里没有出现任何as*适配方法——这正是文档反复强调的“只按需扩展”configureJob()之外没有任何多余代码。作为 Job队列生命周期钩子在 Coolify 中的真实用法文档中的 Job Action 完整模式当 Action 需要以队列形式运行时文档给出的项目级模式是骨架完整保留自 SKILL.md?php namespace App\Actions\Demo; use App\Models\Demo; use DateTime; use Lorisleiva\Actions\Concerns\AsAction; use Lorisleiva\Actions\Decorators\JobDecorator; class GetDemoData { use AsAction; public int $jobTries 3; public int $jobMaxExceptions 3; public function getJobRetryUntil(): DateTime { return now()-addMinutes(30); } public function getJobBackoff(): array { return [60, 120]; } public function getJobUniqueId(Demo $demo): string { return $demo-id; } public function handle(Demo $demo): void { // Core business logic. } public function asJob(JobDecorator $job, Demo $demo): void { // Queue-specific orchestration and retry behavior. $this-handle($demo); } }各成员的含义“仅按需使用”成员作用$jobTries队列执行的最大尝试次数$jobMaxExceptions未处理异常达到该次数后直接判失败getJobRetryUntil()绝对重试截止时间DateTimegetJobBackoff()每次重试的退避策略int或按次数组getJobUniqueId(...)Unique Job 的去重键asJob(JobDecorator $job, ...)访问 attempt 元数据、做队列专属分支Coolify 源码中的两类真实配置Coolify 中定义configureJob(JobDecorator $job)的 Action 有三个分别展示了两种典型的队列控制写法指定队列——StartDatabasepublic function configureJob(JobDecorator $job): void { $job-onQueue(deployment_queue()); }所有数据库启动任务统一进入部署队列避免与高频检查类任务互相挤占。声明式队列属性——DeployServiceApplication 直接声明public string $jobQueue high;让服务部署任务走高优先级队列其handle(...)内部则只关心远程docker compose up -d编排。更完整的 Job 参考dispatch 家族、JobDecorator全部钩子见 references/job.md要点包括异步dispatch(...)、同步dispatchSync(...)/dispatchNow(...)、响应后执行dispatchAfterResponse(...)、条件派发dispatchIf/dispatchUnless链式编排Action::withChain([...])-dispatch(...)或Bus::chain([...])-dispatch()配合makeJob()/makeUniqueJob()包装JobDecorator钩子configureJob()、getJobMiddleware()、$jobConnection、$jobQueue、$jobTries、$jobMaxExceptions、$jobBackoff/getJobBackoff()、$jobTimeout、$jobRetryUntil/getJobRetryUntil()、getJobDisplayName()、getJobTags()、getJobUniqueId()/$jobUniqueId、getJobUniqueFor()/$jobUniqueFor、getJobUniqueVia()、$jobDeleteWhenMissingModels/getJobDeleteWhenMissingModels()以及失败回调jobFailed(?Throwable $e, ...$parameters)测试断言助手assertPushed()/assertNotPushed()/assertPushedOn(queue, times, callback)回调可接收 Action 实例、派发参数、JobDecorator实例和队列名。一个能体现入口点切换的调用链API 控制器 DatabasesController 中十余处StartDatabase::dispatch($database)走队列而同一 Action 在 RestartDatabase 内部走StartDatabase::run($database)同步执行——同一个handle(...)两种传输方式业务逻辑零改动。作为 Controller / Listener / Command三种入口点在文档中的接线规则都很紧凑Controller路由直接指向类invokable 风格如Route::post(/articles/{id}/publish, PublishArticle::class)需要 HTTP 适配时加asController(...)并返回响应输入来自 HTTP 时叠加rules()或自定义 validator 钩子。Listener在EventServiceProvider中注册 Action 类为监听器用asListener(EventName $event)收到事件后委托给handle(...)。Command定义$commandSignature与$commandDescription属性实现asCommand(Illuminate\Console\Command $command)控制台 IO 只留在该方法内。对应的深入参考分别为 references/controller.md、references/listener.md、references/command.md属性注解方式见 references/with-attributes.md。测试策略双层验证与 AsFake 全家族双层测试矩阵文档要求“业务正确性”与“入口点接线”分开验证handle(...)直测真实依赖 工厂数据验证业务规则本身入口点测试分别针对asController打路由、asJobQueue::fake()assertPushed*、asListener派发事件后断言交互、asCommandartisan 命令 输出断言。推荐的测试矩阵为业务规则测试、HTTP 接线测试下游 Action 用shouldRun/shouldNotRunfake、Job 接线测试dispatch 后断言下游调用、事件监听测试事件触发后断言交互、控制台测试运行命令断言调用与输出。最小执行单元示例php artisan test --compact --filterPublishArticle。AsFake 方法族2.x文档按“你想证明什么”来区分每个 fake 方法的适用场景mock()整体替换为 mock适合严格期望与参数断言PublishArticle::mock() -shouldReceive(handle) -once() -with(42) -andReturnTrue();partialMock()部分 mock保留真实行为只桩掉某个昂贵/内部方法PublishArticle::partialMock() -shouldReceive(fetchRemoteData) -once() -andReturn([ok true]);spy()间谍不预定义期望、事后验证“是否以 X 被调用”$spy PublishArticle::spy()-allows(handle)-andReturnTrue(); // 执行触发 Action 的代码… $spy-shouldHaveReceived(handle)-with(42);shouldRun()mock()-shouldReceive(handle)的快捷式适合紧凑的编排断言PublishArticle::shouldRun()-once()-with(42)-andReturnTrue();shouldNotRun()mock()-shouldNotReceive(handle)的快捷式适合守卫分支/分支覆盖测试allowToRun()spy 放行handle既让执行继续又能断言交互$spy PublishArticle::allowToRun()-andReturnTrue(); // … $spy-shouldHaveReceived(handle)-once();isFake()/clearFake()检测类是否当前被替换、清理 fake 防止跨测试泄漏expect(PublishArticle::isFake())-toBeFalse(); PublishArticle::mock(); expect(PublishArticle::isFake())-toBeTrue(); PublishArticle::clearFake(); expect(PublishArticle::isFake())-toBeFalse();实践默认值分支测试优先shouldRun()/shouldNotRun()提升可读性行为大体真实、只需调用验证时用spy()/allowToRun()交互契约严格且要快速失败时用mock()fake 可能泄漏时在清理阶段调clearFake()副作用隔离原则——只 fake 被测 Action 边界而不是 fake 一切。Pest 风格示例与仓库中的测试现实文档给出的 Pest 风格示例it(dispatches the downstream action, function () { SendInvoiceEmail::shouldRun()-once()-withArgs(fn (int $invoiceId) $invoiceId 0); FinalizeInvoice::run(123); }); it(does not dispatch when invoice is already sent, function () { SendInvoiceEmail::shouldNotRun(); FinalizeInvoice::run(123, alreadySent: true); });对照 Coolify 的测试目录可以看到落地方式tests/Feature下的 500 余个测试文件广泛使用Queue::fake()、Bus::fake()以及 Action 的派发断言来验证 Job 接线例如 LifecycleApisTest.php 中多处Queue::fake()ApplicationPreviewQueueAdvancementTest.php 对预览部署队列推进做断言。从源码结构看Coolify 更倾向于以Queue/Busfacade fake 验证“Action 作为 Job 是否被推入预期队列”这与技能文档中 Job 入口点的assertPushed*断言体系是同一套验证思路。排障清单与常见陷阱技能文档收尾部分给出可直接执行的检查清单与陷阱列表值得原样保留排障清单确认类使用了AsAction且命名空间匹配自动加载可用composer show lorisleiva/laravel-actions先确认包已安装以 Controller 使用时检查路由注册使用dispatch时检查队列配置$jobQueue/configureJob/config/queue.php事件到监听器的映射在EventServiceProvider中核对传输层关注点留在as*适配方法里不要混进handle(...)。常见陷阱把 HTTP 响应/重定向逻辑写进handle(...)而不是asController(...)在多个as*方法中重复业务规则而不是委托给handle(...)以为 Listener 接线可以省略显式注册只测入口点、漏测handle(...)直接行为对一次性、单上下文逻辑过度使用 Action无复用压力时保持普通 Service。小结Coolify 的app/Actions目录是 SKILL.md 所述模式的完整实例StartDatabase、DeployServiceApplication等 Action 把远程 Docker 编排、服务器管理、数据库生命周期等业务逻辑收敛进强类型的handle(...)再用configureJob()/$jobQueue声明队列归属、用::run()与::dispatch()在同步/异步两种传输之间自由切换测试层则以Queue::fake()、Bus::fake()加上 Action fake 家族完成双层验证。如果你要在类似 Coolify 的大型 Laravel 项目中新增可复用操作直接按“骨架 → 选入口点 → 补队列钩子 → 双层测试”的工作流推进即可得到结构一致、可预测测试的代码。【免费下载链接】coolifyAn open-source, self-hostable PaaS alternative to Vercel, Heroku Netlify that lets you easily deploy static sites, databases, full-stack applications and 280 one-click services on your own servers.项目地址: https://gitcode.com/GitHub_Trending/co/coolify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

MicroPython RP2040 DMA编程实战:连续数据采集与ADC后台采样 2026/9/7 16:26:34

MicroPython RP2040 DMA编程实战:连续数据采集与ADC后台采样

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
三步免费解析八大网盘真实直链:网盘直链下载助手完整指南 2026/9/7 16:26:34

三步免费解析八大网盘真实直链:网盘直链下载助手完整指南

三步免费解析八大网盘真实直链:网盘直链下载助手完整指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天…

阅读更多 →
Claude Code 实战指南:终端 AI 编程助手的安装、Token 控制与 MCP 玩法 2026/9/7 16:26:34

Claude Code 实战指南:终端 AI 编程助手的安装、Token 控制与 MCP 玩法

从小在一个“能跑就行”的遗留项目里翻数据流,翻到怀疑人生,是我第一次认真用 Claude Code 的契机。当时任务本身不复杂:给一个老模块加新功能,但这个模块的调用链横跨了六个文件、两层抽象,还夹杂着多处动态拼接的方法…

阅读更多 →
从Fork到PR:开源贡献完整流程与Git操作实战指南 2026/9/7 16:26:34

从Fork到PR:开源贡献完整流程与Git操作实战指南

从看源码到自己提PR,这中间到底卡在哪?这是我在带团队和做开源项目维护时最常被问到的问题。很多人clone一个开源项目下来跑通很容易,但真到要给上游仓库提交代码,就完全不知道该从哪里下手了。一个典型的PR(Pull Requ…

阅读更多 →
DETR端到端目标检测:从Transformer原理到实战踩坑全解析 2026/9/7 16:26:34

DETR端到端目标检测:从Transformer原理到实战踩坑全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
CentOS 7安装Docker完整指南:从yum配置到MySQL部署实战 2026/9/7 16:23:33

CentOS 7安装Docker完整指南:从yum配置到MySQL部署实战

CentOS 7安装Docker,这可能是刚入行运维、或者自己折腾服务器的人绕不开的第一道坎。我最早是在一台CentOS 7虚拟机上踩完这个流程,当时照着网上的教程一步步敲,结果不是yum源配错就是Docker服务启动失败,两个周末全耗在上面。后来…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞