where(function ($query) { $query->whereNull('next_run_at') ->orWhere('next_run_at', '<=', now()); }) ->get(); foreach ($schedules as $schedule) { // Skip if there's already a running or pending migration $existingRun = MigrationRun::where('schedule_id', $schedule->id) ->whereIn('status', ['pending', 'running']) ->latest() ->first(); if ($existingRun) { continue; // Skip this schedule, migration already in progress } // Create migration run and dispatch job $migrationRun = MigrationRun::create([ 'schedule_id' => $schedule->id, 'status' => 'pending', 'total_tables' => count($schedule->tables), ]); RunMigrationJob::dispatch($migrationRun)->onQueue('default'); } })->name('check-migration-schedules')->everyMinute()->withoutOverlapping(); // Check for schema changes every hour Schedule::command('schema:check-changes') ->hourly() ->withoutOverlapping() ->onOneServer();