Search code examples
laravelscheduled-tasksjob-scheduling

Laravel - Schedule job for each premium users


What I need to do

When user purchase premium, I give him premium money. Every week, I need to give premium money again at subscription time. However, if the user is no longer a subscriber, they should no longer receive their premium money.

Questions

I think I need to use scheduled tasks, but I do not know how to do that on right way.

  1. How to add tasks dynamically ?
  2. Do I need to put the tasks in the database tasks table ?
  3. How to remove task if user is unsubscribed ? (the check is made in my job but how to remove the task if is unsubscribe)

Code

I need to run this task.

   $schedule->job(new CreditPremiumUser($userId))-> weeklyOn(1, '10:42:53');
   // 1 = premium purchase day
   // '10:42:53' = subscription time

Solution

  • What i did

    Create table tasks

      Schema::create('tasks', function (Blueprint $table) {
         $table->id();
         $table->string('type'); // optional
         $table->string('frequency_function');
         $table->string('frequency_params')->nullable(); // optional
         $table->string('job_name')->nullable(); // optional
         $table->integer('user_id')->nullable(); // optional
         $table->timestamps();
       });
       /*
         Example task data
           type = 'subscription_credit'
           frequency_function = 'weeklyOn'
           frequency_params = 'a:2:{i:0;i:3;i:1;s:5:"12:20";}' // serialize(array(3, '12:20'))
           job_name = App/Jobs/Premium/CreditPremiumMoney
           user_id = 1
       */
    

    I need to schedule Job so I have job_name column.

    For example, depending on your needs, you can add command_name column if you want to schedule the execution of a command.

    Update Kernel

    In your App\Console\Kernel.php schedule method write:

    protected function schedule(Schedule $schedule)
    {
        $tasks = Task::all();
        
        foreach ($tasks as $task) {
            $type = $task->type; // optional
            $frequencyFunc = $task->frequency_function;
            $frequencyFuncParams = $task->frequency_params
                ? unserialize($task->frequency_params)
                : [];
            
            if ($type === 'subscription_credit') { // optional
                $job = $task->job_name;
                $userId = $task->user_id;
                $schedule->job(new $job($userId), 'low', 'redis')
                    ->$frequencyFunc(...$frequencyFuncParams);
            } else if ($type === '...') {
                // Other optional type logic
            }
        }
    }
    

    You can remove type condition if you do not need it or add multiple types logic if you need type.

    Try It

    Add all your tasks to your database.

    Local
    Run command php artisan schedule:work and the scheduler will run to process your tasks at the scheduled dataTime

    Production
    Add CRON to your server like here

    On each environment, the scheduler will run every minute and check if there are tasks to execute in tasks table.