Concept: Configurable behavior on event dispatching
antonkomarev opened this issue · comments
How could we override what will happen on Love event will be dispatched?
This question was raised many times before. Each time I've returned to it a new ideas come into my mind but all of them have their pros and cons. Finally I've got all pieces together and ready to share with my vision.
Thanks to Pavel Volkov @volkv for helping me out with better solution.
First, we should encapsulate increment & decrement logic in jobs. Because we will be able to run those jobs from any place in any time without dispatching an event (which may be listened by many listeners at moment). Listeners will become very simple and synchronous but they will dispatch queued jobs.
Second, we should have more control over the queue. Because developers should be able to choose if they want to use stock package behavior or they want to modify it to their application requirements.
I've designed 4 different implementations of the second part. Each implementation will be described in separate comment.
Spoiler: 4th solution will be implemented #145 (comment)
1. Love global jobs connection
Add love.jobs_connection
config value which will affect on all jobs.
return [
// ...other config fields
'jobs_connection' => null,
];
Right now its fine because we have only 2 listeners, but later it might be an issue when only some jobs will require to work synchronously.
Pros:
- Simple
Cons:
- Not extendable
2. Queue options in config
Add love.jobs
config array where we could define jobs queue options specific for each job.
return [
// ...other config fields
'jobs' => [
Cog\Laravel\Love\Reactant\Jobs\IncrementAggregatesJob => [
'connection' => 'custom_connection_name',
'queue' => 'custom_queue_name',
'timeout' => 60,
'delay' => 90,
],
Cog\Laravel\Love\Reactant\Jobs\DecrementAggregatesJob => [
'connection' => 'custom_connection_name',
'queue' => 'custom_queue_name',
'timeout' => 60,
'delay' => 90,
],
],
];
Pros:
- Each job could be fine-tuned for the app requirements
Cons:
- One more place where breaking changes may pop up in future versions
- Hard to maintain
- Not obvious where those options are coming from
3. Love jobs config registry
Add love.jobs
config array which will work as service locator.
return [
// ...other config fields
'jobs' => [
Cog\Laravel\Love\Reactant\Jobs\IncrementAggregatesJob::class => App\Jobs\Love\ReactantIncrementAggregatesJob,
Cog\Laravel\Love\Reactant\Jobs\DecrementAggregatesJob::class => App\Jobs\Love\ReactantDecrementAggregatesJob,
],
]
or
return [
// ...other config fields
'jobs' => [
'reactant_increment_aggregates' => Cog\Laravel\Love\Reactant\Jobs\IncrementAggregatesJob::class,
'reactant_decrement_aggregates' => Cog\Laravel\Love\Reactant\Jobs\DecrementAggregatesJob::class,
],
]
or
return [
// ...other config fields
'jobs' => [
'reactant' => [
'increment_aggregates' => Cog\Laravel\Love\Reactant\Jobs\IncrementAggregatesJob::class,
'decrement_aggregates' => Cog\Laravel\Love\Reactant\Jobs\DecrementAggregatesJob::class,
],
],
]
Pros:
- You can easily replace stock jobs with your own ones
Cons:
- Not obvious where this rebinding is being done
- Not obvious what arguments will be passed in job's __construct method
- One more place where breaking changes may pop up in future versions
4. Love event service provider
Introduce LoveEventServiceProvider
class which will be responsible for registering Event Listeners only.
final class LoveEventServiceProvider extends ServiceProvider
{
public function boot(): void
{
Event::listen(ReactionHasBeenAdded::class, IncrementAggregates::class);
Event::listen(ReactionHasBeenRemoved::class, DecrementAggregates::class);
}
}
For example if you want to update reactant counters synchronously you could follow 3 easy steps.
- You will need to opt-out package discovery:
"extra": {
"laravel": {
"dont-discover": [
"cybercog/laravel-love"
]
}
},
- Register only core
LoveServiceProvider
provider in your application'sAppServiceProvider
:
$this->app->register(\Cog\Laravel\Love\LoveServiceProvider::class);
- Finally, register any custom event listeners in your
EventServiceProvider
. To not reinvent the wheel you could just make a copy of stock Love's listeners and dispatch jobs introduced in #146 onsync
connection:
IncrementAggregatesJob::dispatch()->onConnection('sync');
Pros:
- Easy to opt-out
- Single responsibility
Cons:
- ???