timokoerber/laravel-one-time-operations
Installation:
composer require timokoerber/laravel-one-time-operations
php artisan migrate
one_time_operations table.First Operation:
php artisan operations:make SeedAdminUser
app/Operations/SeedAdminUser.php.handle() method to define your one-time logic (e.g., seeding an admin user).Run Immediately:
php artisan operations:run
Verify:
one_time_operations table for completed entries or debug logs.app/Operations/ (auto-generated by operations:make).database/migrations/[timestamp]_create_one_time_operations_table.php.app/Console/Kernel.php (registers OperationsCommand).Deployment Hooks:
php artisan operations:run in your post-deploy script (e.g., Deployer, GitHub Actions, or deploy.php)..github/workflows/deploy.yml):
- name: Run one-time operations
run: php artisan operations:run --env=production
Conditional Execution:
--env=staging to target specific environments.php artisan operations:run --force to bypass checks (e.g., for local testing).Ordering:
ASeedAdmin.php runs before BUpdatePricing.php).01_, 02_) for explicit ordering if needed.Integration with Jobs/Commands:
use Illuminate\Support\Facades\Artisan;
public function handle() {
Artisan::call('operations:run');
}
public function handle() {
if ($this->shouldRunOperations()) {
Artisan::queue('operations:run');
}
}
Data-Dependent Logic:
OneTimeOperation model to query pending operations:
$pending = OneTimeOperation::where('executed_at', null)->get();
PascalCase for operation files (e.g., CreateInitialData.php).handle() is idempotent (safe to re-run if needed).handle():
\Log::info('Admin user seeded successfully', ['user_id' => $user->id]);
Race Conditions:
handle() or add a lock column to the table.Stuck Operations:
handle() throws an exception, the operation marks as failed but not retried.try-catch and log errors:
try {
$this->performLogic();
} catch (\Exception $e) {
\Log::error("Operation failed: {$e->getMessage()}");
throw $e; // Marks as failed in the DB
}
Environment Mismatches:
app()->environment() in handle()).if (app()->environment('production')) {
// Production-only logic
}
Table Bloat:
one_time_operations table grows indefinitely.cleanup command to purge old entries (e.g., older than 30 days):
php artisan operations:cleanup --days=30
--dry-run to preview operations without executing:
php artisan operations:run --dry-run
-v for detailed logs:
php artisan operations:run -v
SELECT * FROM one_time_operations ORDER BY created_at;
Custom Storage:
OneTimeOperationRepository in AppServiceProvider:
$this->app->bind(
OneTimeOperationRepository::class,
CustomRepository::class
);
Event Listeners:
OperationExecuted events to trigger side effects:
public function handle(OperationExecuted $event) {
// Send Slack notification, etc.
}
Parallel Execution:
run command):
foreach ($operations as $operation) {
RunOperationJob::dispatch($operation);
}
Rollback Support:
rollback() method to operations for undo logic:
public function rollback() {
// Reverse changes made in handle()
}
OperationsCommand to support rollbacks.How can I help you explore Laravel packages today?