Laravel 的 artisan down 命令默认不写入 maintenance 表,仅在 storage/framework/down 写 JSON 文件供中间件读取;需自定义 down:db 和 up:db 命令,分别插入和更新 maintenance_logs 表以支持审计与联动。
artisan down 命令为什么没写入 maintenance 表?
因为 laravel 默认的 artisan down 不操作数据库,它只在 storage/framework/down 写一个 json 文件,供 illuminate\foundation\http\middleware\checkformaintenancemode 中间件读取。所谓“下发维护标识记录”,不是框架默认行为——你要手动存到数据库里,就得自己定义逻辑。
如何在 down 时自动插入 maintenance 记录?
最直接的方式是监听 DownCommand::class 执行后的事件,但 Laravel 没提供原生事件。稳妥做法是重写命令或封装一层:在调用 php artisan down 后,立刻执行自定义逻辑写库。
- 新建命令
php artisan down:db,继承DownCommand,重写handle() - 先调用父类
parent::handle()确保文件写入和 HTTP 响应生效 - 再用 Eloquent 插入一条记录到
maintenance_logs表(需提前建表) - 推荐字段:
started_at(datetime)、reason(text)、user_id(可选,从Auth::id()或Artisan::call()的上下文获取)
示例插入语句:
$this->info('Writing maintenance record...');<br>MaintenanceLog::create([<br> 'started_at' => now(),<br> 'reason' => $this->option('message') ?? 'Scheduled maintenance'<br>]);
up 时要不要删/更新这条记录?
要,否则你会积累一堆“已结束但未标记”的维护记录。但注意:Laravel 的 artisan up 也不触发任何钩子,所以你也得配套写个 up:db 命令。
- 不要直接
delete(),建议加ended_at字段并做update() - 用
whereNull('ended_at')->latest()->first()定位当前生效的记录,避免误关历史条目 - 如果多台机器并发执行
down,要考虑唯一性约束(比如加status字段 + 数据库唯一索引)
为什么不能只靠 storage/down 文件做审计?
因为 storage/framework/down 是纯临时文件:无时间戳、无操作人、不可查询、不持久化(比如容器重启后可能丢失),更没法关联业务系统日志。一旦出问题,你根本说不清“谁、什么时候、为什么”把服务搞挂了。
真正需要审计或联动监控(比如对接企业微信告警、同步到 CMDB),必须走数据库。但代价是:多一次 DB 写入,且要确保该表在维护期间仍可写——别把 maintenance_logs 放在被维护的主库上又没配置降级写法。











