How to run Shell in background from controller and update database on execution in CakePHP - shell

I am working on CakePHP 3.4 project.
I have to execute some command to scan through the files and directories of a particular directory.
This might take long time depending on the size of the directory, therefore I want to run it in background and mark running label in view until it executed successfully.
How can I run a Shell Task in the background from Controller and update database on execution?
I'm new to Shell tasks.

Your thinking along good lines about running this in the background if it is a time consuming task. You will need to use some form of queuing system that allows you to add jobs to a queue that can then get run in the background by running the queue from a cronjob. Take a look at the Queue plugin for doing this.
You'll basically need to create a queue task that contains the functionality that you need running in the background and then add a job to the queue that will run that task in the background. The Queue plugin's documentation shows how to do this and there are a load of example queue tasks included with the plugin.
If you need to indicate the status of the queued job you could save the job's ID in a session and check if it is complete when loading a page.

You can dispatch a Shell task from the controller. If you want to run this in the background you could, for example, run this controller action via JavaScript/Ajax.
// maybe this task runs looooong
set_time_limit(0);
$shell = new ShellDispatcher();
$output = $shell->run(['cake', 'bake', 'model', 'Products']);
if ($output === 0) {
$this->Flash->success('Yep!');
} else {
$this->Flash->error('Nope!');
}
But you could indeed have googled this at least. ;-)
EDIT Forget this one, go for drmonkeyninja’s answer.

Related

Laravel: How to detect if code is being executed from within a queued job, as opposed to manually run from the CLI

I found this similar question How to check If the current app process is running within a queue environment in Laravel
But actually this is the opposite of what I want. I want to be able to distinguish between code being executed manually from an artisan command launched on the CLI, and when a job is being run as a result of a POST trigger via a controller, or a scheduled run
Basically I want to distinguish between when a job is being run via the SYNC driver, manually triggered by the developer with eyes on the CLI output, and otherwise
app()->runningInConsole() returns true in both cases so it is not useful to me
Is there another way to detect this? For example is there a way to detect the currently used queue connection? Keeping in mind that it's possible to change the queue connection at runtime so just checking the value of the env file is not enough

Running commands from Controller async

There is a migration task. User uploads file to the server, then it should be saved and migration command should be run async. The first path works well, there is an issue with the second part.
I've tried to put all code to console command and run it with
Artisan::call('user:migrate', ['user_id' => $userId]);
or
Artisan::queue('user:migrate', ['user_id' => $userId]);
the script works, but not async, controller's function waits for the end.
Also I've tried to create a Job and call it via:
$this->dispatch(new UserMigration($user));
and had the same result, script works but not async. Please help to realize how queues work and that approach is better for my task.
I've not created any queue migrations and configuration, because need this step just async calling.
In order to run tasks asynchronous, the general idea in Laravel is to push jobs to a queue (database table for instance) and have a background process pick them up.
See https://laravel.com/docs/8.x/queues for information directly from the source.
You can start a queue worker using:
php artisan queue:work
Note that this is an ongoing process that doesn't stop unless it's told to do so. This means that any changes you make to the code, will only be reflected once you restart that queue worker. It is therefore important to run php artisan queue:restart (or kill and start the running task) when you deploy your code.
So now your queue worker is running, you can for instance queue an email to be sent (like upon registration), and your controller will respond immediately instead of having to wait for the email to be sent.
Most if not all info can be found in the link above. If you are going to have lots and lots of background tasks, take a look at Laravel Horizon.

Laravel how to stop a scheduled task in php code

I have several scheduled tasks runs in background mode using Laravel scheduler, I want to use php code to control which one to start and which one to stop, I know how to start a scheduled task, but how to stop a scheduled task in PHP code?
I don't see it in the Laravel scheduler doc.
The best way would be to create a flag somewhere (Model, Cache) and check it when the task gets processed.
The queue in Laravel is just that, a queue. It is not meant to hold state or other information.

Hangfire is running jobs sequentially

I am using HangFire hosted by IIS with an app pool set to "AlwaysRunning". I am using the Autofac extension for DI. Currently, when running background jobs with HangFire they are executing sequentially. Both jobs are similar in nature and involve File I/O. The first job executes and starts generating the requisite file. The second job executes and it starts executing. It will then stop executing until the first job is complete at which point the second job is resumed. I am not sure if this is an issue related to DI and the lifetime scope. I tend to think not as I create everything with instance per dependency scope. I am using owin to bootstrap hangfire and I am not passing any BackgroundServer options, nor am I applying any hints via attributes. What would be causing the jobs to execute sequentially? I am using the default configuration for workers. I am sending a post request to web api and add jobs to the queue with the following BackgroundJob.Enqueue<ExecutionWrapperContext>(c => c.ExecuteJob(job.SearchId, $"{request.User} : {request.SearchName}"));
Thanks In Advance
I was looking for that exact behavior recently and I manage to have that by using this attribute..
[DisableConcurrentExecution(<timeout>)]
Might be that you had this attribute applied, either in the job or globally?
Is this what you were looking for?
var hangfireJobId = BackgroundJob.Enqueue<ExecutionWrapperContext>(x => x.ExecuteJob1(arguments));
hangfireJobId = BackgroundJob.ContinueWith<ExecutionWrapperContext>(hangfireJobId, x => x.ExecuteJob2(arguments));
This will basically execute the first part and when that is finished it will start the second part

Running CakePHP Shells on Background

Is it possible for CakePHP to execute a cakephp shell task on background for
i.e running long reports. I would also want to update the current
status back to the user via updating a table during the report
generation and querying using Ajax.
Yes, you can run shells in the background via normal system calls like
/path/to/cake/console/cake -app /path/to/app/ <shell> <task>
The tricky part is to start one asynchronously from PHP; the best option would be to put jobs in a queue and run the shell as a cron job every so often, which then processes the queue. You can then also update the status of the job in the queue and poll that information via AJAX.
Consider implementing it as a daemon: http://pear.php.net/package/System_Daemon

Resources