How can some code in a bundle be executed after booting the Symfony2 kernel?
The code must be run before a request is handled or console command is run.
The code must be executed once, even when the kernel handles multiple requests during its lifetime.
The code must be able to access the bundle configuration. It may therefore not be run to early in the proces.
The reason I need this is that I need to register a stream wrapper. I need to be able to use the bundle configuration since the stream wrapper definitions are defined in the config.
I tried the following:
Implementing the constructor of the bundle class. (This does not work, not all bundles are initialised at this point)
Creating event listeners for kernel.request and console.command (This will cause the code to be executed multiple times when the kernel handles multiple requests during its lifetime.)
You can override the boot method of your bundle.
class MyBundle extends Bundle
{
public function boot()
{
}
}
You can register one service as event listener for both kernel.request and console.command. It will be fired from console and from HTTP request.
Related
I implemented a custom service provider called PermissionServiceProvider, while debugging an issue I found that the boot method is calling periodically. In our testing server it is invoking every minute, whereas in our production server it seems invoking every seconds (invoking faster than the testing server )
Is it normal that service provider boot method is invoking periodically? What controls the periodicity that makes the difference in test and production server?
Attached production log snippet:
I have a problem in a Symfony 4.4 application where there are a dozen listeners listening to a single event that extends Symfony\Contracts\EventDispatcher\Event. The problem is that if one of the listeners throws an exception, then none of the listeners that come after it are executed.
I was looking for a way to catch exceptions from listeners so that this doesn't occur. I tried extending Symfony\Component\EventDispatcher\EventDispatcher and overriding the callListeners() method to include a try/catch so that I could log the exception but continue the execution. But I don't know how to tell Symfony to use my EventDispatcher instead of its own.
I don't know if that's even a recommendable way of solving this problem. Any idea of how I could get this to work, or if there are any other alternatives?
If an exception is thrown, it should either be handled or the execution stopped. That's what exceptions are for.
And the Event Dispatcher component is not meant to be used asynchronously, with fully decoupled listeners. It's executed synchronously by design, had no transport support, and all listeners run on the same request/execution thread.
If one throws an Exception and it's not handled, execution should stop and never reach the next listener.
Even if you were using a fully async solution, like Symfony Messenger with a transport, throwing an exception and not handling it would prevent the execution of any other listeners to the same event.
I think you are using the wrong tools for the job.
Your listeners should not be throwing exceptions if you do not want to stop execution. Handle the exceptions in the listener, and use the opportunity to log, etc.
I want to run a method when every single console command is run, How do I create a listener for all console commands in lumen?
I tried by creating a listener for ConsoleCommandEvent, this event is fired in \Symfony\Component\Console\Application::doRunCommand, but event dispatcher has not been attached (read the comment above the method:
If an event dispatcher has been attached to the application, events are also dispatched during the life-cycle of the command.)
Update Using this event: Illuminate\Console\Events\ArtisanStarting might help to do the job, but it is a different event. By doing so any time that you run php artisan your code will be executed whether you run an actual command or not.
In Laravel you can listen to the CommandStarting event which is also available in illuminate/console.
If you only need to execute some method when each command were executed, you can listen this class.
Illuminate\Console\Events\ArtisanStarting
But i don't know how to get name of every command inside listener.
I have a class in my Symfony 2.3 project that is doing some http requests and takes some time.
I would like to run this task as a background process, so that the server returns an answer to the client and the background process continues running.
Do you know how to do that in Symfony?
I found the Process Component: http://symfony.com/doc/current/components/process.html but I am not sure if I can run a class method from there.
A simple way to do this is to separate the heavy lifting from the response by using a queue and a symfony command to process the queue.
http://symfony.com/doc/current/components/console/introduction.html
Create a symfony command that processes the jobs added to a queue, then add the work to be done to the queue from your controller. The queue will probably be implemented as a database table of jobs.
That way you can return a success response to the user and run a cron job on the server regularly to process the work you require.
This is something you could easily do with enqueue library. First, you can choose from a variety of transports, such as AMQP, STOMP, Redis, Amazon SQS, Filesystem and so on.
Secondly, That's super easy to use. Let's start from installation:
You have to install the enqueue/enqueue-bundle library and one of the transports. Assuming you choose the filesystem enqueue/fs library:
composer require enqueue/enqueue-bundle enqueue/fs
Now let's see how you can send messages from your POST script:
<?php
use Enqueue\Client\ProducerInterface;
use Symfony\Component\DependencyInjection\Container;
/** #var Container $container */
/** #var ProducerInterface $producer */ $producer = $container->get('enqueue.client.producer');
$producer->sendCommand('a_background_task', 'task_data');
For the consumption, you have to create a processor service and tag it with enqueue.client.processor tag:
<?php
use Enqueue\Client\CommandSubscriberInterface;
use Enqueue\Psr\PsrContext;
use Enqueue\Psr\PsrMessage;
use Enqueue\Psr\PsrProcessor;
class BackgroundTask implements PsrProcessor, CommandSubscriberInterface
{
public static function getSubscribedCommand()
{
// do job
return self::ACK;
}
public function process(PsrMessage $message, PsrContext $context)
{
return 'a_background_task';
}
}
And run a consumer with a command:
./bin/console enqueue:consume --setup-broker -vvv
On the prod you most likely need more then one consumer and if the process exists it has to be restarted. To address this you need a sort of process manager. There several options:
http://supervisord.org/ - You need extra service. It has to be configured properly.
A pure PHP process manager like this. Based on Symfony process component and pure PHP code. It can handle process reboot, correct exit on sigterm signal and a lot more.
A php\swoole process manager like this. It requires a swoole PHP extension but it is performance is amazing.
I have a Zend Application that is running fine.
I have created a Zend Queue script in my library to run some emailing process to members of the site.
The application has many Models that are working well, but when I try and initiate the application in my queue script, it doesn't run.
The only reason I can see for this is a custom helper that extends Zend_Controller_Action_Helper_Redirector. This redirector checks if https is required.
Without initiating the application the run around I have to do to get my queue is nigh impossible.
In my script I am calling from Supervisrd, I am setting up my environment and $application->bootstrap()->run();
I then call the scripts class, but it does not venture past the ->run().
The redirector helper calls exit(), which is why it's not working. I'd rewrite the endpoint to remove the call to redirect, or write a different endpoint for consumption by the CLI job handled by supervisord.