Anvil
Anvil - The mobile companion for Laravel Forge. Available now. Download for iOS

Events

Laravel Patches dispatches events throughout the patch lifecycle, allowing you to hook into the execution process for logging, notifications, monitoring, or custom behavior.

Available Events

PatchExecuting

Dispatched before a patch's up() method runs.

Properties:

  • string $patch - The patch name
  • int $batch - The batch number
  • object $instance - The patch instance

Example:

1use Rappasoft\LaravelPatches\Events\PatchExecuting;
2 
3Event::listen(PatchExecuting::class, function (PatchExecuting $event) {
4 Log::info("About to run patch: {$event->patch} in batch {$event->batch}");
5 
6 // Send notification
7 Notification::send($admins, new PatchStarting($event->patch));
8});

PatchExecuted

Dispatched after a patch successfully executes.

Properties:

  • string $patch - The patch name
  • int $batch - The batch number
  • ?array $log - The patch logs
  • int $executionTime - Execution time in milliseconds
  • float $memoryUsed - Memory used in MB

Example:

1use Rappasoft\LaravelPatches\Events\PatchExecuted;
2 
3Event::listen(PatchExecuted::class, function (PatchExecuted $event) {
4 Log::info("Patch {$event->patch} completed in {$event->executionTime}ms");
5 
6 // Alert if patch took too long
7 if ($event->executionTime > 30000) { // 30 seconds
8 Slack::send("Slow patch detected: {$event->patch} took {$event->executionTime}ms");
9 }
10 
11 // Log metrics to monitoring service
12 Metrics::timing('patch.execution_time', $event->executionTime, [
13 'patch' => $event->patch,
14 'batch' => $event->batch,
15 ]);
16});

PatchFailed

Dispatched when a patch throws an exception.

Properties:

  • string $patch - The patch name
  • int $batch - The batch number
  • Throwable $exception - The exception that was thrown
  • int $executionTime - Time before failure in milliseconds

Example:

1use Rappasoft\LaravelPatches\Events\PatchFailed;
2 
3Event::listen(PatchFailed::class, function (PatchFailed $event) {
4 Log::error("Patch {$event->patch} failed", [
5 'exception' => $event->exception->getMessage(),
6 'trace' => $event->exception->getTraceAsString(),
7 'batch' => $event->batch,
8 ]);
9 
10 // Send urgent notification
11 Notification::send($admins, new PatchFailedNotification($event));
12 
13 // Create rollback plan
14 IssueTracker::create([
15 'title' => "Patch failed: {$event->patch}",
16 'description' => $event->exception->getMessage(),
17 'severity' => 'critical',
18 ]);
19});

PatchRollingBack

Dispatched before a patch's down() method runs.

Properties:

  • string $patch - The patch name
  • object $instance - The patch instance

Example:

1use Rappasoft\LaravelPatches\Events\PatchRollingBack;
2 
3Event::listen(PatchRollingBack::class, function (PatchRollingBack $event) {
4 Log::warning("Rolling back patch: {$event->patch}");
5 
6 // Backup data if needed
7 if ($event->instance instanceof CriticalPatch) {
8 BackupService::createSnapshot();
9 }
10});

PatchRolledBack

Dispatched after a patch successfully rolls back.

Properties:

  • string $patch - The patch name
  • int $executionTime - Rollback time in milliseconds

Example:

1use Rappasoft\LaravelPatches\Events\PatchRolledBack;
2 
3Event::listen(PatchRolledBack::class, function (PatchRolledBack $event) {
4 Log::info("Rolled back patch: {$event->patch} in {$event->executionTime}ms");
5 
6 Cache::tags('patches')->flush();
7});

Registering Event Listeners

In EventServiceProvider

1use Rappasoft\LaravelPatches\Events\{
2 PatchExecuting,
3 PatchExecuted,
4 PatchFailed,
5 PatchRollingBack,
6 PatchRolledBack
7};
8 
9protected $listen = [
10 PatchExecuting::class => [
11 LogPatchExecution::class,
12 NotifyAdministrators::class,
13 ],
14 PatchExecuted::class => [
15 RecordMetrics::class,
16 ClearCache::class,
17 ],
18 PatchFailed::class => [
19 AlertTeam::class,
20 LogFailure::class,
21 ],
22];

Using Closures

1// In AppServiceProvider boot() method
2Event::listen(PatchExecuted::class, function ($event) {
3 // Handle event
4});

Using Event Subscribers

1class PatchEventSubscriber
2{
3 public function handlePatchExecuting(PatchExecuting $event): void
4 {
5 // ...
6 }
7 
8 public function handlePatchExecuted(PatchExecuted $event): void
9 {
10 // ...
11 }
12 
13 public function handlePatchFailed(PatchFailed $event): void
14 {
15 // ...
16 }
17 
18 public function subscribe(Dispatcher $events): array
19 {
20 return [
21 PatchExecuting::class => 'handlePatchExecuting',
22 PatchExecuted::class => 'handlePatchExecuted',
23 PatchFailed::class => 'handlePatchFailed',
24 ];
25 }
26}

Common Use Cases

1. Performance Monitoring

1Event::listen(PatchExecuted::class, function ($event) {
2 Metrics::histogram('patch.duration', $event->executionTime);
3 Metrics::histogram('patch.memory', $event->memoryUsed);
4});

2. Slack Notifications

1Event::listen(PatchExecuted::class, function ($event) {
2 Slack::send("โœ… Patch completed: {$event->patch} ({$event->executionTime}ms)");
3});
4 
5Event::listen(PatchFailed::class, function ($event) {
6 Slack::send("โŒ Patch failed: {$event->patch}\n{$event->exception->getMessage()}");
7});

3. Audit Logging

1Event::listen([PatchExecuted::class, PatchFailed::class], function ($event) {
2 AuditLog::create([
3 'action' => 'patch_executed',
4 'patch' => $event->patch,
5 'batch' => $event->batch,
6 'status' => $event instanceof PatchFailed ? 'failed' : 'success',
7 'user' => auth()->user()?->email,
8 'timestamp' => now(),
9 ]);
10});

4. Cache Invalidation

1Event::listen(PatchExecuted::class, function ($event) {
2 // Clear specific cache after certain patches
3 if (str_contains($event->patch, 'cache')) {
4 Cache::flush();
5 }
6});

5. Database Backups

1Event::listen(PatchExecuting::class, function ($event) {
2 // Backup before critical patches
3 if ($event->instance->isCritical()) {
4 Artisan::call('snapshot:create');
5 }
6});

Event Data Access

All events are serializable and can be queued:

1Event::listen(PatchExecuted::class, function ($event) {
2 ProcessPatchMetrics::dispatch($event)->onQueue('metrics');
3});

Disabling Events

If you need to run patches without triggering events:

1Event::fake([
2 PatchExecuting::class,
3 PatchExecuted::class,
4]);
5 
6Artisan::call('patch');

Or in tests:

1Event::fake();
2// Run patches
3Event::assertDispatched(PatchExecuted::class);