Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concept: Configurable behavior on event dispatching #145

Closed
antonkomarev opened this issue Feb 8, 2020 · 5 comments
Closed

Concept: Configurable behavior on event dispatching #145

antonkomarev opened this issue Feb 8, 2020 · 5 comments

Comments

@antonkomarev
Copy link
Member

antonkomarev commented Feb 8, 2020

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)

@antonkomarev
Copy link
Member Author

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

@antonkomarev
Copy link
Member Author

antonkomarev commented Feb 8, 2020

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

@antonkomarev
Copy link
Member Author

antonkomarev commented Feb 8, 2020

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

@antonkomarev
Copy link
Member Author

antonkomarev commented Feb 8, 2020

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.

  1. You will need to opt-out package discovery:
"extra": {
    "laravel": {
        "dont-discover": [
            "cybercog/laravel-love"
        ]
    }
},
  1. Register only core LoveServiceProvider provider in your application's AppServiceProvider:
$this->app->register(\Cog\Laravel\Love\LoveServiceProvider::class);
  1. 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 Extract logic from Reactant Listeners to Reactant Jobs #146 on sync connection:
IncrementAggregatesJob::dispatch()->onConnection('sync');

Pros:

  • Easy to opt-out
  • Single responsibility

Cons:

  • ???

@antonkomarev
Copy link
Member Author

This concept has been implemented in these PRs: #146 #147

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant