- 新增 FixStuckDocuments 命令用于修复卡住的文档 - 支持批量检测和修复超时的转换任务 - 改进重试按钮,支持 failed/processing/pending 状态 - 在确认对话框中显示当前状态和错误信息 - 提供 dry-run 模式预览修复操作
104 lines
3.3 KiB
PHP
104 lines
3.3 KiB
PHP
<?php
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use App\Models\Document;
|
||
use Illuminate\Console\Command;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
class FixStuckDocuments extends Command
|
||
{
|
||
/**
|
||
* 命令签名
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $signature = 'documents:fix-stuck
|
||
{--timeout=30 : 超过多少分钟未完成视为卡住(默认30分钟)}
|
||
{--status=processing : 要修复的状态(processing/pending)}
|
||
{--dry-run : 仅显示将要修复的文档,不实际执行}';
|
||
|
||
/**
|
||
* 命令描述
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $description = '修复卡在转换中但实际已失败的文档';
|
||
|
||
/**
|
||
* 执行命令
|
||
*/
|
||
public function handle(): int
|
||
{
|
||
$timeout = (int) $this->option('timeout');
|
||
$status = $this->option('status');
|
||
$dryRun = $this->option('dry-run');
|
||
|
||
$this->info("正在查找卡住的文档...");
|
||
$this->info("状态: {$status}");
|
||
$this->info("超时时间: {$timeout} 分钟");
|
||
|
||
// 查找卡住的文档
|
||
$stuckDocuments = Document::where('conversion_status', $status)
|
||
->where('updated_at', '<', now()->subMinutes($timeout))
|
||
->get();
|
||
|
||
if ($stuckDocuments->isEmpty()) {
|
||
$this->info('✓ 没有发现卡住的文档');
|
||
return self::SUCCESS;
|
||
}
|
||
|
||
$this->warn("发现 {$stuckDocuments->count()} 个卡住的文档:");
|
||
|
||
// 显示文档列表
|
||
$tableData = $stuckDocuments->map(function ($doc) {
|
||
return [
|
||
'ID' => $doc->id,
|
||
'标题' => \Illuminate\Support\Str::limit($doc->title, 40),
|
||
'状态' => $doc->conversion_status,
|
||
'更新时间' => $doc->updated_at->format('Y-m-d H:i:s'),
|
||
'卡住时长' => $doc->updated_at->diffForHumans(),
|
||
];
|
||
})->toArray();
|
||
|
||
$this->table(
|
||
['ID', '标题', '状态', '更新时间', '卡住时长'],
|
||
$tableData
|
||
);
|
||
|
||
if ($dryRun) {
|
||
$this->info('');
|
||
$this->info('这是预览模式,没有实际修改任何数据');
|
||
$this->info('移除 --dry-run 选项以执行修复');
|
||
return self::SUCCESS;
|
||
}
|
||
|
||
// 确认操作
|
||
if (!$this->confirm('是否要将这些文档标记为失败状态?', true)) {
|
||
$this->info('操作已取消');
|
||
return self::SUCCESS;
|
||
}
|
||
|
||
// 修复文档
|
||
$fixed = 0;
|
||
foreach ($stuckDocuments as $document) {
|
||
try {
|
||
$document->update([
|
||
'conversion_status' => 'failed',
|
||
'conversion_error' => "转换任务超时(卡在 {$status} 状态超过 {$timeout} 分钟)",
|
||
]);
|
||
$fixed++;
|
||
$this->line("✓ 已修复: [{$document->id}] {$document->title}");
|
||
} catch (\Exception $e) {
|
||
$this->error("✗ 修复失败: [{$document->id}] {$document->title} - {$e->getMessage()}");
|
||
}
|
||
}
|
||
|
||
$this->info('');
|
||
$this->info("修复完成!共修复 {$fixed} 个文档");
|
||
$this->info('现在可以在管理界面使用"重试转换"功能重新处理这些文档');
|
||
|
||
return self::SUCCESS;
|
||
}
|
||
}
|