Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

franklinIwobi's avatar

Should I use Laravel Job or Schedules?

I have an investment model on my laravel project, an investment can have a status of pending, active, cancelled or completed, when an investment is activated i want the status to be updated to active, an email sent to the investment 'user' email and the investment start and end date set, however i also want the system to automatically revisit that investment based on its term ('daily', 'hourly, 'weekly', 'monthly', or 'yearly'), the system should add the term profit (it is stored on the investment table) to the investment user's balance, and continue this way until the investment end date has reached, then the investment status changes to completed. How do you think i should implement this logic into my code?

For more context, let's say a user invests $20 in a plan that pays 0.02% hourly interest for seven days, at the end of the seven days, the user must have accumulated a sum of $2.00672 but every hour he gets $0.0004, so i want to design a system that is smart enough to know the plan interval and add the profit to the user balance until the end date of the plan.

This is what i have for now

public function approve(Investment $investment)
    {
        if ($investment->status !== InvestmentStatus::PENDING) {
            return back()->with('error', 'Invalid operation!');
        }

        if ($investment->term === 'days') {
            $endDate = now()->addDays($investment->duration); //basically translates to 7 days (using the above scenrio i gave)
        } elseif($investment->term === 'hours') {
            $endDate = now()->addHours($investment->duration);
        } elseif($investment->term === 'months') {
            $endDate = now()->addMonths($investment->duration);
        } elseif($investment->term === 'weeks') {
            $endDate = now()->addWeeks($investment->duration);
        } elseif($investment->term === 'years') {
            $endDate = now()->addYears($investment->duration * 365);
        } else {
            throw new Exception("Invalid investment term!", 1);
        }

        $investment->update([
            'status' => InvestmentStatus::ACTIVE,
            'start_date' => now(),
            'end_date' => $endDate
        ]);

        $investment->load('user');

        InvestmentActivated::dispatch($investment);

        return back()->with('success-form', 'Investment activated');
    }

Note: the InvestmentActivated::class is an event and what it only does for now is send an email to the user

0 likes
3 replies
LaryAI's avatar
Level 58

To implement the logic you've described, you should use both Laravel Jobs and Schedules. Here's why and how:

  1. Laravel Jobs: Use jobs to handle the immediate actions that need to occur when an investment is approved, such as updating the status, setting the start and end dates, and sending an email to the user. Jobs are also useful for handling the profit addition at each interval because they can be dispatched at any time and can be delayed to run at a specific time in the future.

  2. Laravel Schedules: Use the task scheduler to periodically check for investments that need to have their profits added based on their term. The scheduler can run a command every minute that checks for any investments that need updating and dispatches jobs accordingly.

Here's an example of how you might implement this:

First, create a new job to handle the profit addition:

php artisan make:job AddInvestmentProfit

In the AddInvestmentProfit job, you would have something like this:

public function handle()
{
    // Logic to add the term profit to the user's balance
    // Check if the investment end date has been reached
    // If so, update the investment status to completed
}

Next, you would dispatch this job within your approve method at the appropriate intervals:

use Illuminate\Support\Facades\Bus;

public function approve(Investment $investment)
{
    // ... existing code ...

    // Dispatch the job to run at the investment's interval
    switch ($investment->term) {
        case 'hourly':
            $delay = now()->addHour();
            break;
        case 'daily':
            $delay = now()->addDay();
            break;
        // Add cases for 'weekly', 'monthly', 'yearly'
        default:
            throw new Exception("Invalid investment term!", 1);
    }

    Bus::chain([
        new AddInvestmentProfit($investment),
        // You can chain multiple jobs if needed
    ])->delay($delay)->dispatch();

    return back()->with('success-form', 'Investment activated');
}

Finally, you would set up a scheduled task in app/Console/Kernel.php to dispatch jobs for investments that need their profits added:

protected function schedule(Schedule $schedule)
{
    $schedule->call(function () {
        // Get investments that need their profits added
        $investments = Investment::where('status', InvestmentStatus::ACTIVE)
                                 ->where('end_date', '>', now())
                                 ->get();

        foreach ($investments as $investment) {
            // Calculate the next profit addition time based on the term
            // Dispatch the AddInvestmentProfit job if it's time to add profit
        }
    })->everyMinute(); // Run every minute to check for due investments
}

This setup allows you to handle immediate actions with jobs and use the scheduler to periodically check and dispatch jobs for ongoing tasks like adding profits to investments. Remember to test thoroughly to ensure that the timing and intervals are working as expected.

gych's avatar

You can combine both, I would shedule to run the job at specific intervals. A job will be useful when there is a lot of data to handle, which can increase by time. The job can then process the data for all users that invested.

Snapey's avatar

anything you want to do in the background should be started by the scheduler; but of course the scheduler might just put a job on a queue

The important question is, what do you want users to see when they log into their account and view their investment? Their balance this minute, this hour, at the end of yesterday? There is no point in calculating the balance when nobody sees it?

If the rate of interest is fixed then you dont need to calculate anything in the background just calculate it at point of enquiry. If interest fluctuates daily then you must calculate the total daily, especially if it is compounded

Please or to participate in this conversation.