当前位置: 首页 > article >正文

hyperf 事故复盘与演练平台(工程版) 开源完整流程(从 0 到持续维护)=)====写一个开源项目全流程

一套可直接落地的 **Hyperf 事故复盘与演练平台工程版**开源方案覆盖 从0搭建到持续维护并给出关键代码骨架可运行方向。 ---1)平台目标工程版 MVP 先做这8个核心能力1. 事故登记与状态流转发现 -处理中 -已恢复 -已复盘2. 事故时间线Timeline自动沉淀3. 复盘报告模板化生成5 Whys CAPA4. 演练计划定时演练、手动演练5. 演练执行记录步骤、结果、评分6. 行动项Owner、截止时间、跟踪状态7. 指标看板MTTA、MTTR、复发率、演练通过率8. API Webhook对接告警平台/IM ---2)推荐仓库结构 hyperf-incident-drill/ ├─ app/ │ ├─ Controller/ │ │ ├─ IncidentController.php │ │ ├─ PostmortemController.php │ │ ├─ DrillPlanController.php │ │ └─ MetricsController.php │ ├─ Model/ │ │ ├─ Incident.php │ │ ├─ IncidentTimeline.php │ │ ├─ Postmortem.php │ │ ├─ ActionItem.php │ │ ├─ DrillPlan.php │ │ └─ DrillRun.php │ ├─ Service/ │ │ ├─ IncidentService.php │ │ ├─ PostmortemService.php │ │ ├─ DrillService.php │ │ └─ MetricsService.php │ ├─ Job/ │ │ ├─ DrillRunJob.php │ │ └─ ReminderActionItemJob.php │ ├─ Crontab/ │ │ └─ DrillSchedulerCrontab.php │ └─ Middleware/ │ └─ AuthzMiddleware.php ├─ config/autoload/ │ ├─ routes.php │ ├─ async_queue.php │ ├─ crontab.php │ └─ databases.php ├─ migrations/ ├─ tests/ ├─ docker-compose.yml ├─ .github/workflows/ci.yml ├─ README.md ├─ SECURITY.md └─ LICENSE ---3)从0初始化composercreate-project hyperf/hyperf-skeleton hyperf-incident-drillcdhyperf-incident-drillcomposerrequire hyperf/db-connection hyperf/databasecomposerrequire hyperf/async-queue hyperf/rediscomposerrequire hyperf/crontab hyperf/validationcomposerrequire ramsey/uuid nesbot/carboncomposerrequire--devphpunit/phpunit phpstan/phpstan friendsofphp/php-cs-fixer ---4)数据库设计关键表4.1incidents事故主表 Schema::create(incidents,function(Blueprint$table){$table-bigIncrements(id);$table-string(incident_no,64)-unique();$table-string(title,200);$table-tinyInteger(severity)-default(2);//1~4$table-tinyInteger(status)-default(1);//1open2mitigating3recovered4reviewed$table-string(service,100)-nullable();$table-string(commander,64)-nullable();$table-timestamp(detected_at)-nullable();$table-timestamp(mitigated_at)-nullable();$table-timestamp(resolved_at)-nullable();$table-timestamp(reviewed_at)-nullable();$table-json(tags)-nullable();$table-timestamps();$table-index([status,severity]);$table-index([detected_at]);});4.2incident_timelines时间线 Schema::create(incident_timelines,function(Blueprint$table){$table-bigIncrements(id);$table-unsignedBigInteger(incident_id);$table-timestamp(event_time);$table-string(event_type,50);// alert/mitigation/recovery/note$table-text(content);$table-string(operator,64)-nullable();$table-timestamps();$table-index([incident_id,event_time]);});4.3postmortems复盘报告 Schema::create(postmortems,function(Blueprint$table){$table-bigIncrements(id);$table-unsignedBigInteger(incident_id)-unique();$table-text(impact_summary)-nullable();$table-json(root_causes)-nullable();$table-json(five_whys)-nullable();$table-json(lessons)-nullable();$table-tinyInteger(status)-default(1);//1draft2published$table-timestamps();});4.4action_items改进行动项 Schema::create(action_items,function(Blueprint$table){$table-bigIncrements(id);$table-unsignedBigInteger(incident_id)-nullable();$table-unsignedBigInteger(postmortem_id)-nullable();$table-string(title,200);$table-string(owner,64);$table-date(due_date)-nullable();$table-tinyInteger(priority)-default(2);//1high2med3low$table-tinyInteger(status)-default(1);//1todo2doing3done4overdue$table-timestamps();$table-index([owner,status]);$table-index([due_date,status]);});4.5drill_plans / drill_runs演练计划与执行 Schema::create(drill_plans,function(Blueprint$table){$table-bigIncrements(id);$table-string(name,150);$table-string(target_service,100);$table-string(scenario,200);$table-string(cron_expr,64)-nullable();$table-json(steps);// 演练步骤$table-tinyInteger(enabled)-default(1);$table-timestamp(next_run_at)-nullable();$table-timestamps();});Schema::create(drill_runs,function(Blueprint$table){$table-bigIncrements(id);$table-unsignedBigInteger(plan_id);$table-string(run_no,64)-unique();$table-tinyInteger(status)-default(1);//1running2pass3fail$table-unsignedInteger(score)-default(0);$table-json(result)-nullable();$table-timestamp(started_at)-nullable();$table-timestamp(finished_at)-nullable();$table-timestamps();$table-index([plan_id,created_at]);});---5)核心代码骨架5.1事故服务状态流转 时间线 app/Service/IncidentService.php?php declare(strict_types1);namespace App\Service;use App\Model\Incident;use App\Model\IncidentTimeline;use Hyperf\DbConnection\Db;use Ramsey\Uuid\Uuid;final class IncidentService{publicfunctioncreate(array$data): Incident{returnDb::transaction(function()use($data){$incidentIncident::query()-create([incident_noINC-.date(Ymd).-.substr(Uuid::uuid4()-toString(),0,8),title$data[title],severity(int)($data[severity]??2),status1,service$data[service]?? null,commander$data[commander]?? null,detected_at$data[detected_at]?? date(Y-m-d H:i:s),tags$data[tags]??[],]);$this-appendTimeline((int)$incident-id,alert,incident created,$data[operator]??system);return $incident;});} public function transition(int $incidentId,int $toStatus,string $operator,string $note):void { Db::transaction(function()use($incidentId,$toStatus,$operator,$note){ $incidentIncident::query()-findOrFail($incidentId);$incident-status$toStatus;if($toStatus2)$incident-mitigated_atdate(Y-m-d H:i:s);if($toStatus3)$incident-resolved_atdate(Y-m-d H:i:s);if($toStatus4)$incident-reviewed_atdate(Y-m-d H:i:s);$incident-save();$this-appendTimeline($incidentId,status_change,status-{$toStatus};{$note},$operator);});} public function appendTimeline(int $incidentId,string $type,string $content,string $operator):void { IncidentTimeline::query()-create([ incident_id$incidentId,event_timedate(Y-m-d H:i:s),event_type$type,content$content,operator$operator,]);} }5.2演练执行 Job异步 app/Job/DrillRunJob.php?php declare(strict_types1);namespace App\Job;use App\Model\DrillPlan;use App\Model\DrillRun;use Hyperf\AsyncQueue\Job;use Ramsey\Uuid\Uuid;final class DrillRunJob extends Job { public function __construct(public int $planId){} public function handle():void { $planDrillPlan::query()-findOrFail($this-planId);$runDrillRun::query()-create([ plan_id$plan-id,run_noDR- . date(YmdHis). - . substr(Uuid::uuid4()-toString(),0,6),status1,started_atdate(Y-m-d H:i:s),]);$steps$plan-steps??[];$result[];$score100;$failedfalse;foreach($steps as $idx$step){ try {//这里替换为真实演练动作调用压测平台/故障注入接口/脚本网关 $result[][step$idx1,name$step[name]??step,oktrue];} catch(\Throwable $e){ $failedtrue;$score-20;$result[][step$idx1,name$step[name]??step,okfalse,error$e-getMessage()];} } $run-status$failed?3:2;$run-scoremax(0,$score);$run-result$result;$run-finished_atdate(Y-m-d H:i:s);$run-save();} }5.3定时调度演练每分钟扫描 app/Crontab/DrillSchedulerCrontab.php?php declare(strict_types1);namespace App\Crontab;use App\Model\DrillPlan;use App\Job\DrillRunJob;use Hyperf\AsyncQueue\Driver\DriverFactory;use Hyperf\Crontab\Annotation\Crontab;use Hyperf\DbConnection\Db;use Cron\CronExpression;final class DrillSchedulerCrontab { public function __construct(private DriverFactory $driverFactory){} #[Crontab(rule:*****,memo:schedule drill plans,singleton:true)] public function execute():void { Db::transaction(function(){ $plansDrillPlan::query()-where(enabled,1)-lockForUpdate()-get();foreach($plans as $plan){ if(!$plan-cron_expr)continue;if($plan-next_run_atstrtotime((string)$plan-next_run_at)time())continue;$this-driverFactory-get(default)-push(new DrillRunJob((int)$plan-id));$plan-next_run_atCronExpression::factory($plan-cron_expr)-getNextRunDate()-format(Y-m-d H:i:s);$plan-save();}});}}5.4指标服务MTTA / MTTR app/Service/MetricsService.php?php declare(strict_types1);namespace App\Service;use App\Model\Incident;use Carbon\Carbon;final class MetricsService{publicfunctionsummary(): array{$incidentsIncident::query()-whereNotNull(detected_at)-get();$mtta[];$mttr[];foreach($incidentsas$i){if($i-mitigated_at){$mtta[]Carbon::parse($i-detected_at)-diffInMinutes(Carbon::parse($i-mitigated_at));}if($i-resolved_at){$mttr[]Carbon::parse($i-detected_at)-diffInMinutes(Carbon::parse($i-resolved_at));}}return[incident_total$incidents-count(),mtta_mincount($mtta)? round(array_sum($mtta)/ count($mtta),2):null,mttr_mincount($mttr)? round(array_sum($mttr)/ count($mttr),2):null,];}}---6)API 路由最小闭环 config/autoload/routes.php?php use Hyperf\HttpServer\Router\Router;use App\Controller\IncidentController;use App\Controller\PostmortemController;use App\Controller\DrillPlanController;use App\Controller\MetricsController;Router::addGroup(/api,function(){Router::post(/incidents,[IncidentController::class,create]);Router::post(/incidents/{id:\d}/transition,[IncidentController::class,transition]);Router::post(/incidents/{id:\d}/timeline,[IncidentController::class,appendTimeline]);Router::post(/incidents/{id:\d}/postmortem,[PostmortemController::class,upsert]);Router::post(/drill/plans,[DrillPlanController::class,create]);Router::post(/drill/plans/{id:\d}/run,[DrillPlanController::class,runNow]);Router::get(/metrics/summary,[MetricsController::class,summary]);});---7)本地运行与基础设施 docker-compose.yml最小 version:3.8services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: incident ports:[3306:3306]redis: image: redis:7 ports:[6379:6379]---8)CI/CD开源必须 .github/workflows/ci.yml 至少包含 -composervalidate - php-cs-fixer --dry-run - phpstan analyse - phpunit - 集成测试创建 incident -状态流转 -生成 postmortem -触发演练 run ---9)开源发布完整流程1. LICENSEMIT / Apache-2.02. README.md快速启动、状态机、API 示例、架构图3. SECURITY.md漏洞提交通道和 SLA4. Issue/PR 模板5. 首版标签v0.1.06. 发布后维护 CHANGELOG.mdBreaking Change 要写迁移步骤 ---10)持续维护路线图建议 - v0.1事故、时间线、复盘、演练、指标闭环 - v0.2RBAC、多租户、Webhook飞书/Slack/钉钉 - v0.3演练评分模型RTO/RPO/响应协作得分 - v1.0审计日志、SSO、插件化演练动作K8s/DB/Cache ---11)工程版最容易踩坑的点1. 演练任务与生产任务混跑缺少资源隔离2. 时间线依赖人工补录导致复盘不完整3. MTTR 口径不统一检测时间/恢复时间定义混乱4. Action Item 没有逾期提醒和闭环追踪5. 演练“只执行不复盘”无法沉淀改进资产 --- 这套骨架已经能作为开源首版先上线 Incident Timeline Postmortem Drill Metrics 主链路再迭代权限、通知和插件能力。

相关文章:

hyperf 事故复盘与演练平台(工程版) 开源完整流程(从 0 到持续维护)=)====写一个开源项目全流程

一套可直接落地的 **Hyperf 事故复盘与演练平台(工程版)**开源方案,覆盖 从 0搭建到持续维护,并给出关键代码骨架(可运行方向)。--- …...

Phi-3.5-mini-instruct C语言编程助手:指针与内存管理详解

Phi-3.5-mini-instruct C语言编程助手:指针与内存管理详解 1. 为什么需要这个教程 指针是C语言的灵魂,也是初学者最容易卡壳的地方。很多人第一次接触指针时,脑子里全是问号:这到底是个地址还是个值?为什么要有指针&…...

ChatArena多智能体对话框架:从核心原理到实战应用

1. 项目概述:从零理解ChatArena,一个多智能体对话竞技场如果你对AI智能体(Agent)的开发、评测或者多智能体协作与竞争感兴趣,那么Farama Foundation旗下的ChatArena项目,绝对是一个值得你投入时间研究的“宝…...

BERT模型解析与应用:从原理到实践优化

1. BERT模型基础解析BERT(Bidirectional Encoder Representations from Transformers)是2018年由Google推出的基于Transformer架构的自然语言处理模型。与传统的单向语言模型不同,BERT采用了双向上下文理解机制,使其在各种NLP任务…...

构建混合特征机器学习流水线:TF-IDF与LLM嵌入的工程实践

1. 项目概述:构建混合特征机器学习流水线在自然语言处理(NLP)领域,特征工程的质量往往直接决定模型性能上限。传统方法如TF-IDF擅长捕捉关键词统计特征,而现代LLM嵌入(如BERT、GPT)则能理解语义…...

Keil MDK vs. Zephyr RTOS vs. FreeRTOS:5款主流嵌入式平台实测对比,哪款真正支持Phi-3-mini C API插件热加载?

更多请点击: https://intelliparadigm.com 第一章:嵌入式 C 语言与轻量级大模型适配 在资源受限的嵌入式设备(如 Cortex-M4/M7、ESP32、RISC-V MCU)上部署大语言模型,核心挑战在于将高精度浮点计算、庞大参数量与有限…...

AWS CodeBuild 配置 PHP 8.0 运行时的正确方法

本文详解如何在 aws codebuild 中成功启用 php 8.0 运行时,指出常见错误根源(镜像版本不匹配),并提供可直接使用的 buildspec.yml 配置与验证步骤。 本文详解如何在 aws codebuild 中成功启用 php 8.0 运行时,指出…...

为什么GitHub Codespaces能秒启而你的本地Dev Container总卡在“Building…”?(底层镜像分层缓存全解密)

更多请点击: https://intelliparadigm.com 第一章:GitHub Codespaces与本地Dev Container的启动性能鸿沟 GitHub Codespaces 依赖云端虚拟机资源,每次启动需拉取镜像、挂载远程存储、初始化网络策略并同步用户配置,导致冷启动耗时…...

【国家级嵌入式系统安全白皮书援引标准】:为什么Linux内核5.20+、Zephyr 4.0、AUTOSAR R22-10已全面禁用裸指针算术?

更多请点击: https://intelliparadigm.com 第一章:现代 C 语言内存安全编码规范 2026 避坑指南 C 语言在嵌入式系统、操作系统内核与高性能服务中仍不可替代,但其原始内存模型正面临日益严峻的安全挑战。2026 年起,主流编译器&am…...

统计学习与机器学习:差异、联系与融合实践

1. 应用统计与机器学习的紧密关系解析作为一名长期在数据科学领域工作的实践者,我经常被问到统计学与机器学习之间的区别与联系。这两个领域确实有着千丝万缕的联系,但各自又保持着独特的视角和方法论。简单来说,机器学习更关注算法实现和预测…...

Java的java.lang.ModuleLayer层次结构与模块隔离在复杂应用中的组织

Java模块化系统中的层次隔离艺术 在微服务与云原生架构盛行的当下,Java的模块化系统(JPMS)通过java.lang.ModuleLayer为复杂应用提供了动态模块管理与隔离能力。ModuleLayer通过父子层次结构实现模块的沙箱化部署,允许同一应用内…...

nli-MiniLM2-L6-H768效果展示:630MB模型精准识别蕴含/矛盾/中立关系

nli-MiniLM2-L6-H768效果展示:630MB模型精准识别蕴含/矛盾/中立关系 1. 开篇:小巧但强大的自然语言推理模型 在自然语言处理领域,判断两个句子之间的关系是一项基础但至关重要的任务。nli-MiniLM2-L6-H768模型以仅630MB的体积,实…...

EgerGergeeert数据库课程设计助手:从需求分析到SQL生成

EgerGergeeert数据库课程设计助手:从需求分析到SQL生成 1. 课程设计的痛点与解决方案 每到学期末,计算机专业的学生们都会面临一个共同的挑战——数据库课程设计。这个看似简单的任务,实际上包含了需求分析、概念设计、逻辑设计、物理实现和…...

5分钟快速上手:让Windows任务栏焕然一新的终极美化方案

5分钟快速上手:让Windows任务栏焕然一新的终极美化方案 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB 你是否厌倦了Windows系…...

灵感画廊部署案例:树莓派5+eGPU边缘端轻量级艺术终端可行性验证

灵感画廊部署案例:树莓派5eGPU边缘端轻量级艺术终端可行性验证 1. 项目背景与目标 最近在折腾一个挺有意思的项目,叫“灵感画廊”。这名字听起来就很有艺术感,对吧?它本质上是一个基于Stable Diffusion XL 1.0的AI绘画工具&…...

Java应用性能监控利器MyPerf4J:无侵入方法级监控实战指南

1. 项目概述与核心价值最近在排查一个线上服务的性能瓶颈,发现传统的日志埋点和监控系统在定位高并发下的方法级性能问题时,总是隔靴搔痒。要么是粒度太粗,看不到具体是哪个方法拖了后腿;要么是开销太大,开启监控后服务…...

神经网络过拟合防治:噪声注入原理与实践指南

1. 神经网络训练中的过拟合问题与噪声注入原理在深度学习实践中,我们经常遇到一个令人头疼的现象:模型在训练集上表现优异,但在测试集上却差强人意。这种现象被称为过拟合(Overfitting),尤其在小数据集场景…...

如何提交网站到谷歌网站收录? Shopify卖家必看:解决产品页不收录难题 | 零代码指南

爬虫每天造访数以亿计的新页面。机器阅读代码,给出评分,决定是否将其放入庞大的资料库。这套机制冷酷无情,只认数字与规则。在浏览器输入特定指令查验当下状态是一切动作的起点。键盘敲下site加上你的域名,屏幕跳出的数字展现了店…...

ECOC多分类方法:原理、实现与优化策略

1. 理解错误校正输出编码(ECOC)的核心思想在机器学习领域,多分类问题一直是个有趣的挑战。想象一下,你手头有一堆专门解决"是或否"问题的工具(比如逻辑回归、支持向量机),但现在需要处…...

2024机器学习工程师薪资趋势与技能溢价分析

1. 2024年机器学习行业薪资与就业市场全景扫描过去三年机器学习工程师的薪资中位数增长了47%,这个数字背后反映的是整个行业供需关系的深刻变化。我最近刚帮团队招聘了一位有3年经验的计算机视觉工程师,开出的package比两年前同等资历候选人高出30%依然竞…...

Apache Commons FileUpload 2.0:Java 文件上传的终极解决方案

Apache Commons FileUpload 2.0:Java 文件上传的终极解决方案 【免费下载链接】commons-fileupload Apache Commons FileUpload is a robust, high-performance, file upload capability to your servlets and web applications 项目地址: https://gitcode.com/gh…...

基于strands-agents的AI代理开发:从工具调用到生产部署

1. 项目概述:一个面向AI代理开发的Python SDK如果你最近在尝试构建一个能够自主执行复杂任务的AI代理,比如让它帮你分析数据、自动回复邮件,甚至管理一个项目流程,那你大概率会遇到一个核心难题:如何让大语言模型&…...

炉石传说自动化脚本:3步实现智能对战与卡组策略优化

炉石传说自动化脚本:3步实现智能对战与卡组策略优化 【免费下载链接】Hearthstone-Script Hearthstone script(炉石传说脚本) 项目地址: https://gitcode.com/gh_mirrors/he/Hearthstone-Script 炉石传说脚本(Hearthstone-…...

AI编码助手PUA技能:打破AI惰性,提升调试与代码审查效率

1. 项目概述:当AI开始“内卷”——PUA技能如何重塑你的编码助手如果你用过Claude Code、Cursor或者GitHub Copilot,大概率经历过这种场景:你让AI帮你调试一个复杂的API连接错误,它试了两三次,然后告诉你“我无法解决这…...

NBTExplorer:5个关键功能解密Minecraft数据编辑难题

NBTExplorer:5个关键功能解密Minecraft数据编辑难题 【免费下载链接】NBTExplorer A graphical NBT editor for all Minecraft NBT data sources 项目地址: https://gitcode.com/gh_mirrors/nb/NBTExplorer 想象一下,你花费数月时间建造的Minecra…...

机器学习模型比较:McNemar检验原理与实践

1. 机器学习分类器比较的统计检验挑战在机器学习模型评估中,我们经常需要比较两个分类器的性能差异。传统方法如交叉验证虽然可靠,但当面对大型深度学习模型时,这种方法会面临严峻挑战——训练单个模型可能就需要数周时间,更不用说…...

Intv_ai_mk11模型微调入门:使用自有数据提升垂直领域表现

Intv_ai_mk11模型微调入门:使用自有数据提升垂直领域表现 1. 为什么需要微调大模型 你可能已经用过一些现成的大模型,比如ChatGPT或者Claude,它们能处理各种通用问题。但当你想让模型在特定领域(比如法律咨询或医疗问答&#xf…...

DeepSeek-R1-Distill-Qwen-7B在工业质检中的创新应用

DeepSeek-R1-Distill-Qwen-7B在工业质检中的创新应用 1. 工业质检的痛点与AI解决方案 工业质检一直是制造业的核心环节,但传统方法面临诸多挑战。人工检测效率低、容易疲劳,视觉检测系统又难以处理复杂缺陷和变化场景。每个新缺陷类型都需要重新编程规…...

YOLOv8鹰眼检测数据导出教程:如何保存检测结果?

YOLOv8鹰眼检测数据导出教程:如何保存检测结果? 1. 引言:为什么需要导出检测数据? 在实际项目中,仅仅在WebUI上查看检测结果往往不够。我们通常需要将检测到的物体信息(如类别、位置、置信度)…...

实测Qwen2.5-Coder-1.5B:自动生成Python代码效果展示

实测Qwen2.5-Coder-1.5B:自动生成Python代码效果展示 写代码,尤其是写那些重复、繁琐或者需要特定算法的代码,是很多开发者头疼的事。有没有一个工具,能听懂你的需求,然后“唰”地一下,把完整、可运行的代…...