0

Users are able to set up a marketing email send time within my app for random dates as they need them. It is crucial that the emails start to go out exactly when they are scheduled. So, the app needs to create something that fires one time for a specific group of emails at a specific date and time down to the minute. There will be many more dates for other sends in the future, but they are all distinct (so need something other than 'run every xxx date')

I could have a Scheduler task that runs every minute that looks at the dates of any pending tasks in the database and moves to the command that sends those that need sending. But I'm running a multi-tenanted app -- likely not overlap, but seems like a huge hit to multiple databases every minute for every tenant to search through potentially thousands of records per tenant.

What I need (I think) is a way to programmatically set a schedule for each send date, and then remove it. I liked this answer or perhaps using ->between($startMin, $endMin), without the every xxx instruction, or even using the cron function within Scheduler to set up one single time for each group that needs to be sent. Not sure I'm using this the way it was intended though?

Would this even work? I programmatically created a schedule from within a test method, and it was added to the schedule queue based on the dump of the $schedule I created, showing all schedules - but it did not show up via this method found from this answer:

$schedule = app()->make(\Illuminate\Console\Scheduling\Schedule::class);

$events = collect($schedule->events())->filter(function (\Illuminate\Console\Scheduling\Event $event) {
    return stripos($event->command, 'YourCommandHere');
});

It also did not output anything, so I'm wondering if programmatically creating a schedule outside of Kernel.php is not the way to go.

Is there another way? I don't know scheduler well enough to know if these one-off schedules permanently remain somewhere, are they deleted after their intended single use, taking up memory, etc?

Really appreciate any help or guidance.

Watercayman
  • 7,970
  • 10
  • 31
  • 49
  • Presumably the time is set in a database somewhere so you can run something every minute to check whether it's time to send an email. – apokryfos Aug 30 '20 at 04:52
  • Yes, that's correct. I'm just worried about the efficiency of hitting 20-30 tenant databases to check against potentially hundreds of records every minute. Maybe I'm just paranoid :) But I was also thinking of creating a table with *just* the dates to fire - then the command will search to get all the records with a corresponding date. Delete the dates after firing, and the table is tiny. Maybe a middle ground? – Watercayman Aug 30 '20 at 05:08
  • 1
    I would do a load test before going ahead to do optimisations but yes I think this is the ideal way. You can also probably [queue a job with a delay](https://laravel.com/docs/7.x/queues#delayed-dispatching) but I'm not sure how reliable or accurate that is for potentially long delays. – apokryfos Aug 30 '20 at 05:28
  • Thanks very much @apokryfos. I'll likely do exactly that. Thought about the queue thing too, but this could be days/weeks out, so not a workable solution. – Watercayman Aug 30 '20 at 05:43

0 Answers0