更新
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\command;
|
||||
|
||||
use app\adminapi\logic\tcm\MobileRecordingMediaLogic;
|
||||
use app\common\service\mobilerecording\MobileRecordingObjects;
|
||||
use app\common\service\mobilerecording\MobileRecordingWork;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\console\input\Option;
|
||||
use think\facade\Db;
|
||||
|
||||
/** Schedule once per minute with a non-overlap lock; contains no cloud credentials in arguments. */
|
||||
final class MobileRecordingCosWork extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('mobile-recording:cos-work')->setDescription('推进手机录音COS提交及私有对象删除重试')
|
||||
->addOption('dry-run', null, Option::VALUE_NONE, '只统计,不调用COS')
|
||||
->addOption('limit', null, Option::VALUE_REQUIRED, '最多处理的上传数,1至100', '5')
|
||||
->addOption('seconds', null, Option::VALUE_REQUIRED, '上传调度时间预算,1至300秒;单个COS请求仍有10秒超时', '20');
|
||||
}
|
||||
protected function execute(Input $input, Output $output): int
|
||||
{
|
||||
try {
|
||||
$limit = max(1, min(100, (int) $input->getOption('limit')));
|
||||
$seconds = max(1, min(300, (int) $input->getOption('seconds')));
|
||||
$dry = (bool) $input->getOption('dry-run');
|
||||
$deadline = microtime(true) + $seconds;
|
||||
$counts = MobileRecordingObjects::cleanup(1, $dry);
|
||||
$counts += ['uploads_selected' => 0, 'uploads_completed' => 0, 'uploads_deferred' => 0,
|
||||
'uploads_denied' => 0, 'staging_cleaned' => 0];
|
||||
$rows = Db::name('mobile_recording_upload')->alias('u')
|
||||
->join([Db::name('mobile_recording_binding')->getTable() => 'b'], 'b.id=u.binding_id')
|
||||
->leftJoin([Db::name('mobile_recording_object')->getTable() => 'o'], 'o.upload_id=u.upload_id')
|
||||
->leftJoin([Db::name('mobile_recording_asset')->getTable() => 'a'], 'a.upload_id=u.upload_id AND a.binding_id=u.binding_id AND a.kind=u.kind')
|
||||
->leftJoin([Db::name('mobile_recording_work')->getTable() => 'w'], 'w.upload_id=u.upload_id')
|
||||
->whereRaw("((u.state='uploading' AND u.received_bytes=u.size_bytes) OR (u.state='complete' AND o.state IN ('pending','finalizing','verifying')) OR (u.state='complete' AND o.state='ready' AND a.upload_id IS NOT NULL AND COALESCE(w.staging_cleaned,0)=0))")
|
||||
->whereRaw('COALESCE(w.next_retry_at,0) <= ' . time())
|
||||
->field('u.upload_id,u.state,o.state AS object_state,b.admin_id,b.diagnosis_id')
|
||||
->orderRaw('COALESCE(w.last_attempt_at,0),u.updated_at,u.upload_id')->limit($limit)->select()->toArray();
|
||||
$counts['uploads_selected'] = count($rows);
|
||||
if (!$dry) {
|
||||
foreach ($rows as $row) {
|
||||
if (microtime(true) >= $deadline) { break; }
|
||||
try {
|
||||
if ($row['state'] === 'complete' && $row['object_state'] === 'ready') {
|
||||
if (!MobileRecordingObjects::cleanupStaging($row['upload_id'], true)) { throw new \DomainException('Media publication no longer active'); }
|
||||
$counts['staging_cleaned']++;
|
||||
} elseif ($row['state'] === 'complete') { MobileRecordingMediaLogic::migrateLocal($row['upload_id']); $counts['uploads_completed']++; }
|
||||
else { MobileRecordingMediaLogic::complete(['upload_id' => $row['upload_id'], 'diagnosis_id' => (int) $row['diagnosis_id']], (int) $row['admin_id']); }
|
||||
if ($row['state'] === 'uploading') {
|
||||
// complete may publish successfully while best-effort unlink failed. Keep that task retryable.
|
||||
if (!MobileRecordingObjects::cleanupStaging($row['upload_id'], true)) { throw new \DomainException('Media publication no longer active'); }
|
||||
$counts['uploads_completed']++;
|
||||
}
|
||||
MobileRecordingWork::attempted($row['upload_id']);
|
||||
} catch (\Throwable $e) {
|
||||
MobileRecordingWork::attempted($row['upload_id'], $e);
|
||||
$counts['uploads_deferred']++;
|
||||
if ($e instanceof \DomainException) { $counts['uploads_denied']++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
$output->writeln('MOBILE_RECORDING_COS_WORK ' . json_encode($counts));
|
||||
return $counts['errors'] > 0 || $counts['uploads_deferred'] > 0 ? 1 : 0;
|
||||
} catch (\Throwable $e) { $output->writeln('MOBILE_RECORDING_COS_WORK storage_or_configuration_error'); return 1; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user