소스 검색

fix: 定时任务添加exception字段,事件改为CronJobProcessing/CronJobProcessed/CronJobFailed

runphp 1 개월 전
부모
커밋
f74fdc39b9

+ 18 - 0
database/migrations/20260729000000_add_exception_to_cron_job_log.php

@@ -0,0 +1,18 @@
+<?php
+
+declare(strict_types=1);
+
+use Phinx\Migration\AbstractMigration;
+
+class AddExceptionToCronJobLog extends AbstractMigration
+{
+    public function change(): void
+    {
+        $table = $this->table('cron_job_log');
+        $table->addColumn('exception', 'text', [
+            'null' => true,
+            'after' => 'success',
+            'comment' => '异常信息',
+        ])->update();
+    }
+}

+ 10 - 0
frontend/admin/views/CronJobLog.vue

@@ -131,6 +131,12 @@
             </el-tag>
           </template>
         </el-table-column>
+        <el-table-column prop="exception" label="异常信息" min-width="200" show-overflow-tooltip>
+          <template #default="{ row }">
+            <span v-if="row.exception" class="exception-text">{{ row.exception }}</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="create_time" label="执行时间" width="180" align="center" />
         <el-table-column label="操作" width="100" align="center" fixed="right">
           <template #default="{ row }">
@@ -374,4 +380,8 @@ onMounted(() => {
   justify-content: flex-end;
   margin-top: 16px;
 }
+
+.exception-text {
+  color: #f56c6c;
+}
 </style>

+ 1 - 0
src/Entity/CronJobLogEntity.php

@@ -88,6 +88,7 @@ class CronJobLogEntity extends BaseEntity
                 'last_time' => $record['create_time'],
                 'duration' => $record['duration'],
                 'success' => $record['success'],
+                'exception' => $record['exception'] ?? null,
             ];
         }, $records);
     }

+ 19 - 0
src/Event/CronJobFailed.php

@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SixShop\System\Event;
+
+use Throwable;
+
+class CronJobFailed
+{
+    public function __construct(
+        public readonly string $name,
+        public readonly string $rule,
+        public readonly string|object $target,
+        public readonly Throwable $throwable,
+        public readonly float $startTime,
+    ) {
+    }
+}

+ 2 - 10
src/Event/CronJobAfterEvent.php → src/Event/CronJobProcessed.php

@@ -4,22 +4,14 @@ declare(strict_types=1);
 
 namespace SixShop\System\Event;
 
-use Throwable;
-
-class CronJobAfterEvent
+class CronJobProcessed
 {
     public function __construct(
         public readonly string $name,
         public readonly string $rule,
         public readonly string|object $target,
+        public readonly float $startTime,
         public readonly mixed $result = null,
-        public readonly ?float $duration = null,
-        public readonly ?Throwable $throwable = null,
     ) {
     }
-
-    public function isSuccessful(): bool
-    {
-        return $this->throwable === null;
-    }
 }

+ 1 - 1
src/Event/CronJobBeforeEvent.php → src/Event/CronJobProcessing.php

@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace SixShop\System\Event;
 
-class CronJobBeforeEvent
+class CronJobProcessing
 {
     public function __construct(
         public readonly string $name,

+ 22 - 8
src/Hook/CronJobHook.php

@@ -6,21 +6,35 @@ namespace SixShop\System\Hook;
 
 use SixShop\Core\Attribute\Hook;
 use SixShop\System\Entity\CronJobLogEntity;
-use SixShop\System\Event\CronJobAfterEvent;
+use SixShop\System\Event\CronJobFailed;
+use SixShop\System\Event\CronJobProcessed;
 
 class CronJobHook
 {
-    /**
-     * 每次任务执行后记录执行日志到数据库
-     */
-    #[Hook(CronJobAfterEvent::class)]
-    public function onJobExecuted(CronJobAfterEvent $event): void
+    #[Hook(CronJobProcessed::class)]
+    public function onJobProcessed(CronJobProcessed $event): void
     {
+        $duration = round(microtime(true) - $event->startTime, 4);
+
+        CronJobLogEntity::create([
+            'name' => $event->name,
+            'rule' => $event->rule,
+            'duration' => $duration,
+            'success' => true,
+        ]);
+    }
+
+    #[Hook(CronJobFailed::class)]
+    public function onJobFailed(CronJobFailed $event): void
+    {
+        $duration = round(microtime(true) - $event->startTime, 4);
+
         CronJobLogEntity::create([
             'name' => $event->name,
             'rule' => $event->rule,
-            'duration' => $event->duration,
-            'success' => $event->isSuccessful(),
+            'duration' => $duration,
+            'success' => false,
+            'exception' => $event->throwable->getMessage(),
         ]);
     }
 }

+ 21 - 17
src/Hook/GatheringCrontabEventHook.php

@@ -8,8 +8,9 @@ use ReflectionClass;
 use ReflectionMethod;
 use SixShop\Core\Attribute\Cron;
 use SixShop\Core\Attribute\Hook;
-use SixShop\System\Event\CronJobAfterEvent;
-use SixShop\System\Event\CronJobBeforeEvent;
+use SixShop\System\Event\CronJobFailed;
+use SixShop\System\Event\CronJobProcessed;
+use SixShop\System\Event\CronJobProcessing;
 use SixShop\System\Event\CrontabWorkerStartEvent;
 use SixShop\System\Event\GetCronJobsEvent;
 use SixShop\System\ExtensionManager;
@@ -32,29 +33,32 @@ class GatheringCrontabEventHook
     private function wrapCallback(callable $callback, string $name, string $rule, object $target): callable
     {
         return function () use ($callback, $name, $rule, $target) {
-            $this->app->event->trigger(new CronJobBeforeEvent($name, $rule, $target));
+            $this->app->event->trigger(new CronJobProcessing($name, $rule, $target));
 
             $startTime = microtime(true);
-            $throwable = null;
             $result = null;
 
             try {
                 $result = $callback();
-            } catch (\Throwable $e) {
-                $throwable = $e;
-                Log::error("Cron job [{$name}] failed: " . $e->getMessage());
-            }
 
-            $duration = microtime(true) - $startTime;
+                $this->app->event->trigger(new CronJobProcessed(
+                    name: $name,
+                    rule: $rule,
+                    target: $target,
+                    startTime: $startTime,
+                    result: $result,
+                ));
+            } catch (\Throwable $e) {
+                Log::error("Cron job [{$name}] failed: " . (string) $e);
 
-            $this->app->event->trigger(new CronJobAfterEvent(
-                name: $name,
-                rule: $rule,
-                target: $target,
-                result: $result,
-                duration: round($duration, 4),
-                throwable: $throwable,
-            ));
+                $this->app->event->trigger(new CronJobFailed(
+                    name: $name,
+                    rule: $rule,
+                    target: $target,
+                    throwable: $e,
+                    startTime: $startTime,
+                ));
+            }
         };
     }