| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- <?php
- namespace App\Module\Transfer\Jobs;
- use App\Module\Transfer\Logics\CallbackLogic;
- use App\Module\Transfer\Models\TransferOrder;
- use App\Module\Transfer\Enums\TransferStatus;
- use UCore\Queue\QueueJob;
- use Illuminate\Support\Facades\Log;
- /**
- * 发送回调通知任务
- */
- class SendCallbackJob extends QueueJob
- {
- private int $orderId;
- private int $retryCount;
- private int $maxRetries;
- /**
- * 任务最大尝试次数
- */
- public int $tries = 1; // 重试逻辑由业务控制
- /**
- * 任务超时时间(秒)
- */
- public int $timeout = 60;
- /**
- * 创建任务实例
- */
- public function __construct(int $orderId, int $retryCount = 0, int $maxRetries = 3)
- {
- $this->orderId = $orderId;
- $this->retryCount = $retryCount;
- $this->maxRetries = $maxRetries;
- parent::__construct([
- 'order_id' => $orderId,
- 'retry_count' => $retryCount,
- 'max_retries' => $maxRetries
- ]);
- // 设置队列名称
- $this->onQueue('transfer_callback');
- }
- /**
- * 执行任务
- */
- public function run(): bool
- {
- try {
- $order = TransferOrder::find($this->orderId);
-
- if (!$order) {
- Log::warning('Transfer order not found for callback', [
- 'order_id' => $this->orderId
- ]);
- return false;
- }
- // 检查订单状态
- if ($order->isFinalStatus()) {
- Log::info('Transfer order already in final status, skipping callback', [
- 'order_id' => $order->id,
- 'status' => $order->status->value
- ]);
- return true;
- }
- // 检查是否支持回调
- if (!$order->transferApp->supportsCallback()) {
- Log::info('Transfer app does not support callback, completing order', [
- 'order_id' => $order->id,
- 'app_id' => $order->transfer_app_id
- ]);
- $order->updateStatus(TransferStatus::COMPLETED);
- return true;
- }
- Log::info('Sending transfer callback', [
- 'order_id' => $order->id,
- 'retry_count' => $this->retryCount,
- 'callback_url' => $order->transferApp->order_callback_url
- ]);
- // 发送回调
- $success = CallbackLogic::sendCallback($order);
- if ($success) {
- Log::info('Transfer callback sent successfully', [
- 'order_id' => $order->id,
- 'retry_count' => $this->retryCount
- ]);
- } else {
- $this->handleCallbackFailure($order);
- }
- } catch (\Exception $e) {
- Log::error('Transfer callback job failed', [
- 'order_id' => $this->orderId,
- 'retry_count' => $this->retryCount,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
- // 处理回调失败
- $order = TransferOrder::find($this->orderId);
- if ($order) {
- $this->handleCallbackFailure($order);
- }
- return false;
- }
- return true;
- }
- /**
- * 获取任务数据
- *
- * @return array
- */
- public function payload()
- {
- return [
- 'order_id' => $this->orderId,
- 'retry_count' => $this->retryCount,
- 'max_retries' => $this->maxRetries
- ];
- }
- /**
- * 处理回调失败
- */
- private function handleCallbackFailure(TransferOrder $order): void
- {
- if ($this->retryCount < $this->maxRetries) {
- // 安排重试
- $nextRetryCount = $this->retryCount + 1;
- $delayMinutes = $this->calculateRetryDelay($nextRetryCount);
- Log::info('Scheduling callback retry', [
- 'order_id' => $order->id,
- 'retry_count' => $nextRetryCount,
- 'delay_minutes' => $delayMinutes
- ]);
- // 更新订单的重试计数
- $callbackData = $order->callback_data;
- $callbackData['retry_count'] = $nextRetryCount;
- $callbackData['last_retry_at'] = now()->toDateTimeString();
- $order->update(['callback_data' => $callbackData]);
- // 调度重试任务
- self::dispatch($order->id, $nextRetryCount, $this->maxRetries)
- ->delay(now()->addMinutes($delayMinutes));
- } else {
- // 达到最大重试次数,记录失败
- Log::error('Transfer callback max retries reached', [
- 'order_id' => $order->id,
- 'retry_count' => $this->retryCount,
- 'max_retries' => $this->maxRetries
- ]);
- // 更新订单状态为失败
- $order->updateStatus(TransferStatus::FAILED, '回调发送失败,已达最大重试次数');
- }
- }
- /**
- * 计算重试延迟时间(指数退避)
- */
- private function calculateRetryDelay(int $retryCount): int
- {
- // 指数退避:1分钟、2分钟、4分钟
- return min(pow(2, $retryCount - 1), 30); // 最大30分钟
- }
- /**
- * 任务失败时的处理
- */
- public function failed(\Throwable $exception): void
- {
- Log::error('Transfer callback job failed permanently', [
- 'order_id' => $this->orderId,
- 'retry_count' => $this->retryCount,
- 'error' => $exception->getMessage()
- ]);
- // 更新订单状态为失败
- $order = TransferOrder::find($this->orderId);
- if ($order && !$order->isFinalStatus()) {
- $order->updateStatus(TransferStatus::FAILED, '回调任务失败: ' . $exception->getMessage());
- }
- }
- /**
- * 获取任务的唯一ID
- */
- public function uniqueId(): string
- {
- return "transfer_callback_{$this->orderId}_{$this->retryCount}";
- }
- /**
- * 静态方法:调度回调任务
- */
- public static function schedule(int $orderId, int $delayMinutes = 0): void
- {
- $job = new self($orderId);
-
- if ($delayMinutes > 0) {
- $job->delay(now()->addMinutes($delayMinutes));
- }
-
- dispatch($job);
- }
- /**
- * 静态方法:立即发送回调
- */
- public static function sendNow(int $orderId): void
- {
- dispatch_sync(new self($orderId));
- }
- /**
- * 静态方法:批量调度回调任务
- */
- public static function scheduleBatch(array $orderIds, int $delayMinutes = 0): void
- {
- foreach ($orderIds as $orderId) {
- self::schedule($orderId, $delayMinutes);
- }
- }
- }
|