skip to Main Content

On my application, users have lists of emails they can send to. Their accounts have settings for the time of day they want emails automatically sent and the timezone they’re in.

I would like to test certain scenarios on when my queues are triggered since each user’s send time may differ drastically.

I’d like to globally set a fake time with carbon.

In public/index.php, I tried to set:

$time = Carbon::create('2020-09-16 00:00:00');
        Carbon::setTestNow($time);

but pieces of my application are not affected.

Is there a global way to set a fake time?


Original question below:

On my application, users have lists of emails they can send to. Their accounts have settings for the time of day they want emails automatically sent and the timezone they’re in.

I have a command that will trigger an event that sends email.

Inside the listener, the handle method looks like:

public function handle(ReviewRequested $event)
    {
        
        $time = Carbon::create(2020, 9, 15, 0);
        Carbon::setTestNow($time);  

        $reviewRequest = $event->reviewRequest;
        Log::info('email sending at ' . $reviewRequest->sent_at . ' and current time is ' . Carbon::now());
        Mail::to($reviewRequest->customer->email)
            ->later($reviewRequest->sent_at, new ReviewRequestMailer($reviewRequest));

    }

Note that I’m faking the time with Carbon and setting it to midnight. In this example, The emails should be sent at 9am. The logged info is as follows:

local.INFO: email sending at 2020-09-15 09:00:00 and current time is 2020-09-15 00:00:00

So the current time is 12AM and I’m queuing these up to get sent at 9AM.

As soon as I run php artisan queue:work, the pending jobs (emails) are immediately run and sent. Why is this happening? They should remain queued until 9AM.

Perhaps queuing is using system time and doesn’t care about what I set in Carbon? How can I resolve this?

Edit: I forgot to mention that I’m using Redis

2

Answers


  1. Check what queue driver you’re using in your .env file. QUEUE_CONNECTION=sync does not allow for any delaying (sync stands for synchronous).

    The quickest way to fix this would be doing the following:

    • change the driver to database QUEUE_CONNECTION=database
    • clear the cached configuration php artisan config:clear
    • publish the migration for the jobs table php artisan queue:table
    • migrate this new table php artisan migrate

    After following these steps, you can now have delayed execution in your queues when you run it with php artisan queue:work

    Login or Signup to reply.
  2. I think you should use Laravel Cron Job for this purpose. you should make a file in App/Console/Commands/YourCronJobFile.php

         <?php
    
         namespace AppConsoleCommands;
    
         use AppTestingCron;
         use IlluminateConsoleCommand;
         use IlluminateSupportFacadesDB;
    
         class TestingCronJob extends Command
       {
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'send:Mail';
    
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'This command is use for test cron jobs.';
    
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }
    
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        DB::table('testing_cron')->insert(['created_at' => now(),'updated_at' => now()]);
    }
    }
    

    Then go to directory App/Console/Kernel.php

     <?php
    
     namespace AppConsole;
    
     use IlluminateConsoleSchedulingSchedule;
     use IlluminateFoundationConsoleKernel as ConsoleKernel;
    
     class Kernel extends ConsoleKernel
    {
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        CommandsTestingCronJob::class
    ];
    
    /**
     * Define the application's command schedule.
     *
     * @param  IlluminateConsoleSchedulingSchedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('send:Mail')->dailyAt('09:00');
    }
    
    /**
     * RegisterController the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__.'/Commands');
    
        require base_path('routes/console.php');
    }
    }
    

    https://laravel.com/docs/7.x/scheduling

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search