syamsoul/laravel-action-delay
Installation:
composer require syamsoul/laravel-action-delay
Publish the config (optional):
php artisan vendor:publish --provider="Syamsoul\ActionDelay\ActionDelayServiceProvider"
First Use Case: Delay a job execution until a specific datetime:
use Syamsoul\ActionDelay\Facades\ActionDelay;
ActionDelay::delayNow(\App\Jobs\ProcessPayment::class, now()->addHours(2));
Where to Look First:
config/action-delay.php for customization (e.g., default queue connection).app/Console/Commands/ for extending or overriding commands.ActionDelay::delayNow(\App\Jobs\SendEmail::class, now()->addMinutes(15));
ActionDelay::delayNow(\App\Jobs\SendEmail::class, now()->addHours(1), [
'user_id' => 1,
'template' => 'welcome'
]);
ActionDelay::delayQuery(
'users',
fn() => User::where('active', true)->count(),
now()->addMinutes(5)
);
ActionDelay::delayQuery(
'user_stats',
fn() => User::withCount('posts')->get(),
now()->addHours(1)
);
ActionDelay::delayCode(
'log_system_health',
fn() => Log::info('System check passed'),
now()->addMinutes(30)
);
ActionDelay::delayArtisan(
'optimize:clear',
now()->addDays(1)
);
config/action-delay.php:
'queue_connection' => 'redis',
'queue' => 'delayed',
DelayedJob model (e.g., app/Models/CustomDelayedJob.php) to add metadata:
use Syamsoul\ActionDelay\Models\DelayedJob as BaseDelayedJob;
class CustomDelayedJob extends BaseDelayedJob {
protected $casts = [
'metadata' => 'array',
];
}
delay:interactive command for prompts:
php artisan delay:interactive
$schedule->command('delay:run')->dailyAt('10:00');
Timezone Mismatches:
config/app.php timezone matches your delayed actions’ expectations.Carbon instances (e.g., now('Asia/Jakarta')) for clarity.Queue Worker Stuck:
php artisan queue:work).storage/logs/laravel.log.Payload Serialization:
json_encode():
ActionDelay::delayNow(\App\Jobs\HandleOrder::class, now()->addHour(), [
'order' => $order->toArray(),
]);
Overlapping Delays:
job_id + delayed_at).Inspect Delayed Jobs:
php artisan tinker
>>> \Syamsoul\ActionDelay\Models\DelayedJob::latest()->get();
Log Execution:
handle() method to your delayed job to log start/end:
public function handle() {
Log::info("Executing delayed job: {$this->job}");
}
Test Locally:
php artisan queue:work --once to manually trigger delayed jobs.Custom Actions:
ActionDelay facade by binding a new command:
ActionDelay::extend('custom', function ($delayAt, $payload) {
// Custom logic (e.g., HTTP request)
});
Event Listeners:
delayed.job.created or delayed.job.executed events:
use Syamsoul\ActionDelay\Events\DelayedJobCreated;
DelayedJobCreated::listen(function ($job) {
// Send notification or update UI
});
Middleware for Jobs:
class ProcessPayment extends Job {
use Dispatchable, InteractsWithQueue;
public function handle() {
// Job logic
}
public function middleware() {
return [new AuthorizeUser()];
}
}
Retries:
config/action-delay.php:
'max_retries' => 3,
'retry_after' => 60, // seconds
Bulk Delaying:
$users = User::where('needs_notification', true)->get();
foreach ($users as $user) {
ActionDelay::delayNow(\App\Jobs\NotifyUser::class, now()->addMinutes(10), ['user_id' => $user->id]);
}
Dynamic Delays:
ActionDelay::delayNow(\App\Jobs\SyncData::class, fn() => now()->addMinutes(rand(5, 30)));
Environment-Specific Delays:
.env:
ACTION_DELAY_DEFAULT_MINUTES=1440 # 24 hours
Monitoring:
Nova::resources([
\Syamsoul\ActionDelay\Nova\DelayedJob::class,
]);
How can I help you explore Laravel packages today?