3

I have a ftp function which moves file from one folder to other(say folder a to folder b) when a button is clicked. It works perfectly. I want a function that will run 30 minutes after the above function is called(i.e. after the file is moved from a to b). How can I schedule such a task in laravel?

I want to do this, because after that file is moved few functions are executed and then if the person forgets to remove the file then that can be dangerous. So I need to check, 30 mins after the file is moved from a to b, whether the file has been moved back or no.

Raj Shah
  • 101
  • 1
  • 10
  • You can use cron for this. Call a method which start a new cron job. [This](https://stackoverflow.com/questions/6548746/how-to-start-stop-a-cronjob-using-php) might be helpful. The problem is to stop cron job after execution. So maybe set up every minute cron which'd check if some files needed to move. – Tarasovych Mar 26 '18 at 06:06
  • did u find solution? – Adam Kozlowski Mar 26 '18 at 06:49
  • @AdamKozlowski no not completely. Working on that, will provide the answer if i find one. I am thinking of making a database entry every time my first function is completed. Then running a function to check the time difference, so that if its 30 mins then the cron should run. – Raj Shah Mar 27 '18 at 05:28
  • You do not understand. Set cron to make it's job every minute. And write code what will be checking if there is 30 min of difference. Make cron to trigger that script every minute. It is really simple. You must devide cron job frequency from code inside that cron. – Adam Kozlowski Mar 27 '18 at 05:42
  • okay, I get it. I will try that. – Raj Shah Mar 27 '18 at 05:47

2 Answers2

4

This sounds like a perfect opportunity to make use of Laravels queues, which also allow for delayed dispatching as you can find in the documentation when looking for queuing and delayed dispatching.

Basically, you will need a job that you can push onto the queue like the following

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class RemoveFileFromFtp implements ShouldQueue
{
    use Dispatchable, Queueable;

    protected $file;

    /**
     * Create a new job instance.
     *
     * @param  string $file
     * @return void
     */
    public function __construct(string $file)
    {
        $this->file = $file;
    }

    /**
     * Execute the job.
     *
     * @param  FtpService $ftpService
     * @return void
     */
    public function handle(FtpService $ftpService)
    {
        $ftpService->removeFileIfExists($this->file);
    }
}

You will then be able to dispatch the job like so:

function doSomethingWithFileOnFtp()
{
    // ... here you can do what you described

    // and then you queue a clean up job for the file
    RemoveFileFromFtp::dispatch($file)->delay(now()->addMinutes(30));
}

Of course this solution expects you to have set up Laravel queues properly. There is different ways you can do this, but I guess the documentation is your best friend regarding this (see here).

Namoshek
  • 5,468
  • 2
  • 16
  • 27
  • I agree that this is the answer. You just need a way to remove the option from the queue if they move forward OR your queued job could just do a safety check before it deletes. – parker_codes Mar 28 '18 at 18:49
  • Tried to hint the safety check with the method name. But of course, this is mandatory (although it would probably not break anything if you'd let it run into an exception). – Namoshek Mar 28 '18 at 18:57
  • Thanks a lot and sorry I just saw your answer. While searching I found the queues few hours ago and have successfully implemented it. It is working just as I wanted it to. I was about to provide the answer, but you did my job. – Raj Shah Mar 29 '18 at 05:25
  • @Namoshek I had one question. Is it possible that instead of using the command php artisan make:job xyz, i directly add the xyz.php file in apps/job folder in my project. – Raj Shah Mar 29 '18 at 06:15
  • 1
    Of course. The `make:` commands are basically just copying templates. Nothing you couldn't do manually . – Namoshek Mar 29 '18 at 06:25
2

You need CRON JOB - Laravel Scheduler

Class example:

namespace App\Console;

use DB;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->call(function () {
            DB::table('recent_users')->delete();
        })->daily();
    }
}

Then you need to switch on cron jobs on server:

* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1

Here you have details: https://laravel.com/docs/5.6/scheduling

And nice video which explains somethings: https://www.youtube.com/watch?v=mp-XZm7INl8

Adam Kozlowski
  • 3,978
  • 1
  • 23
  • 38
  • Using this i was able to create a cron job running every 30 mins. But i want the cron to run 30 mins after i execute a function. – Raj Shah Mar 27 '18 at 05:30
  • A cron job is not suitable as you will run into situations where the cron job is executed a very short time after the creation, if it happens on fixed hours and minutes. A cron job could still work if you perform a check on the age of the file, though. Instead of deleting all files, you could just remove all files older than 30 minutes. But this is not the Laravel way to do it, that's for sure. – Namoshek Mar 28 '18 at 18:40