I was wondering what the difference is between the different command-like classes in Laravel 5.1. As far as I can tell Laravel 5.1 has the following available:
Console commands (artisan make:console)
Commands (artisan make:command)
Handlers (artisan make::command --handler)
Jobs (artisan make:job)
I have come straight from 4.2 to 5.1 so I don't know what happened in between 4.2 and 5.1, but I have been told that the middle one (just commands) are basically not really supposed to be used any more - they are in from when queue-able jobs became 'commands' in 5.0, but Laravel since decided against this, and they're just in for compatibility. However, I'm not 100% on this point, so clarification would be appreciated.
My specific use-case is that I want a place to put a self-contained 'runnable' task. For example, something that will remove files older than 5 days from a given directory (but it could do anything).
At first this sounds like a console command - I want to be able to run it from artisan, for a start. But I may also want it on a schedule (great, artisan schedule:run runs console commands). But I may also want to execute it asynchronously from code. Console commands can be run synchronously with Artisan::call(), but for asynchronous, this is (I think) where queues come in, and it suddenly has to be a job.
Okay so we have a job. We can now add it to a queue from code, but how do we execute it as an artisan command (synchronously)? Can I just create a thin console command and add the DispatchesJobs trait (or the code therein) to it, and then dispatch the job? Does the job always have to go on a queue, or can we make a job execute synchronously (and, ideally, output to the console command's output?) The same question goes for running it on a schedule - am I supposed to create this console command and add that to the scheduler, or can I make the scheduler run the job directly?
And finally, we have 'commands' that aren't console commands nor are they jobs. As I said before, people tell me these are just hangers-on from a Laravel 5.0 code change that was (kinda) reverted. But the artisan make command still exists for them, so they can't be that dead. Also, what's the deal with a self handling command (the default, comes with a handle method) and one that 'requires' a handler class (run artisan make:command --handler)? How do you actually make these execute? Manually with (new App\Command\SomeCommand)->handle(); or (new App\handlers\SomeCommandHandler)->handle(new App\Command\SomeCommand), or is there some hidden system I don't know about (maybe they can be dispatched using the job/queue dispatcher)? Also you can create 'queued' commands artisan make::command --queued, so how do these differ, too?
I guess my question boils down to the following:
What is the real (semantic and functional) difference between them all?
What is the correct way to 'run' them?
Which is best for my purposes of a generally-standalone bit of code that needs to be run, in whatever manner I feel appropriate?
I found information in the documentation on how to use queues and create console commands, but nothing on exactly when to use them or really anything on command classes and handlers.
Related but not exactly the same (also, it's unanswered): Laravel 5.1 commands and jobs
Console Commands
Laravel has had console "commands" for some time. They are basically unchanged, and work as they always have. In simple terms, they are the equivalent of routes for the command line - the entry point into the application. They are in no way related to...
The Command Bus
Laravel 5.0 introduced an implementation of the Command Bus pattern - Command Bus Commands. (I believe these were renamed to Jobs because of the resulting confusion between them and CLI Commands).
A command bus as two parts - an object that represents a command to be executed, with any and all data it needs (the job), and a class to execute the command (the handler).
The Handler
In laravel, you can declare a job to be self handling - that is, it has a handle method itself.
If you want to register a command handler, you can call the following in a service provider:
app('Illuminate\Bus\Dispatcher')->maps(['Job' => 'Handler']);
where Job is the class name for the job, and Handler is the class name for the handler.
The handlers directory in laravel 5.0 was a way of implicitly declaring those relationships (ie. EmailCommand in the commands folder would have an EmailCommandHandler in the handlers folder).
Dispatching a Command
You can use the following to dispatch a command.
app('Illuminate\Bus\Dispatcher')->dispatch(new EmailPersonCommand('email#you.com', $otherdata));
Queues
Jobs, by default, will run as soon as they are called (or dispatched). Setting them as ShouldQueue will always pass them to a queue when they are dispatched.
If you want to run them synchronously sometimes, and asynchronously other times, you can call $dispatcher->dispatchToQueue($job) when you want them to be queued. This is all that happens internally when you pass a ShouldQueue job to ->dispatch().
edit: To Queuing (or not)
I've just had a longer look at the dispatcher. The dispatch method checks if the command is a ShouldQueue, and either forwards it to dispatchToQueue or dispatchNow. You can call either of those methods directly instead of dispatch with your command should you wish to override the default behaviour.
So in your case, depending on what the "default" behaviour of your job is (ie. will it normally be queued?) either:
- have it ShouldQueue, and use dispatchNow in the CLI Command.
- don't have it ShouldQueue, and use dispatchToQueue where you call it in your code.
From the sounds of it, i'd do the former.
I see those "objects" like so: (I added some code examples from one of my side projects)
Console
Things I want to execute from the command line (As you mentioned with your example with "Delete Files older than x"). But the thing is, you could extract the business logic of it to a command.
Example: A console command with fires a command to fetch images from Imgur. The Class FetchImages contains the actual business logic of fetching images.
Command
Class which contains the actual logic. You should also be able to call this command from your application with app()->make(Command::class)->handle().
Example: Command mentioned in Example 1. Contains logic which does the actual API calls to Imgur and process returned data.
Jobs
I made this app with Laravel 5.0 so jobs weren't a thing back then. But as I see it, Jobs are like commands but they are queued and can be dispatched. (As you may have seen in those examples, those commands implement your mentioned Interfaces SelfHandling and ShouldBeQueued).
I see myself as an experienced Laravel Developer but those changes in Commands and Jobs are quite difficult to understand.
EDIT:
From the Laravel Docs:
The app/Commands directory has been renamed to app/Jobs. However, you are not required to move all of your commands to the new location, and you may continue using the make:command and handler:command Artisan commands to generate your classes.
Likewise, the app/Handlers directory has been renamed to app/Listeners and now only contains event listeners. However, you are not required to move or rename your existing command and event handlers, and you may continue to use the handler:event command to generate event handlers.
By providing backwards compatibility for the Laravel 5.0 folder structure, you may upgrade your applications to Laravel 5.1 and slowly upgrade your events and commands to their new locations when it is convenient for you or your team.
Just an addition to the actual answers.
Jobs in Laravel >= 5.1 are Commands Bus in Laravel 5.0.
It is only a naming change because of the confusion between Console\Commands (commands run from the console) and The Command Bus (containing Commands) for the Application Tasks.
You should not confound :
Command Bus : used for "encapsulating tasks your application" (from laravel 5.0 doc) which is now renamed a Jobs
Console\Commands : used for "Artisan [...] the command-line interface included with Laravel" (from laravel 5.1 docs) which is unchanged in Laravel since 4.x
Related
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
I am writing a command which has a lot of service information that I need to see during the command is running.
I am outputing this info simply running echo "some text", and that way I can see what happens when running this command. When the same command is run with scheduler I have to log all this info. So I have to duplicate all the same messages with: Log::info("some text").
If I want to avoid duplication I can create a helper class that can have all this, that I then include in all the service classes that are related to this command and use this helper class to avoid code duplication, but I still feel that this is not ideal solution. Is there maybe a built in way in Laravel on how to sent to console output and Log at the same time?
You could add: ->appendOutputTo('path')); when running your task that execute your command, to store the output messages in your log file. Although, I'm not sure if this will log all console I/O (it will be good to know in case you test it).
Check this.
I have two apps running on the same server.
Now it seems like when adding withoutOverlapping() to the scheduler job and managing the base cronjob via cron itself, these 2 apps are blocking each other in execution.
Could that be?
Yes, withoutOverlapping only works per application.
Laravel creates a file in the storage folder with a hash of the job. This way, if the file exists, Laravel knows the job is still running. The one application cannot possibly know if the other one is currently running a job because it does not have access to the storage folder of the other application.
If your code looks like the following
$schedule->command('process:queue 0')->everyMinute()->withoutOverlapping();
$schedule->command('process:queue 1')->everyMinute()->withoutOverlapping();
It is because same commands with different parameters might bc considered overlapping.
I.e. the hash of the job will consider only the command signature.
I have an external script that changes some tables in a database.
I want to fire some scripts whenever this happens.
I could do this with a PHP/Perl daemon easily, however I wonder if Laravel has something for this.
Don't know if it's relevant for what you're trying to do but you can use the Laravel Scheduler to run a command that checks (every minutes or more) if the database changed.
If you can too, fire a command directly from your external script like
php path/to/artisan your:command-name
Is there way to invoke a CakePHP console shell on server without shell access? I have written a shell for performing some once off (and hence not a cron task) post DB upgrade tasks.
I could always just copy the logic into a temporary controller, call its actions via http and then delete it, but was wondering if there was a better way to go about it.
It seems that this is a one off script you might want to typically be running after DB updates right?
If that's the case, you can make it part of your "DB update script"
If you use anything like capistrano, you can include there too.
In all cases, if you don't want to touch the shell, I agree that having a controller to call the console code (or any php file running exec() as mentioned previously) would do the trick.
Also, if you want to run it just once and have it scheduled - don't forget that you have the "at" command (instead of cron) which will run it at that scheduled date (see http://linux.about.com/library/cmd/blcmdl1_at.htm)
Hope it helps,
Cheers,
p.s: if its a console shell and you don't want to run it from the console, then just don't make it a console shell.
I have to agree with elvy. Since this is something that you need to do once in a while after other events have happened, why not just create an 'admin' area for your application and stick code for that update in there?
you may be able to use php's exec function to call it from any old php script.
http://www.php.net/exec