-
Notifications
You must be signed in to change notification settings - Fork 11k
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
[8.x] Delay dispatching listeners until transaction commits #35434
[8.x] Delay dispatching listeners until transaction commits #35434
Conversation
What if we added an interface like ShouldWaitForCommit / WaitsForTransactionCommit instead of using properties? Can be also added to jobs. |
Very strange implementation. Why the event should know when it will be dispatch? Event is just a message, it must be decoupled from environment and has no affect to dispatch process. If you want to dispatch the event after transaction is commited, use something like public function dispatchAfterCommit(object $event, string $target = TransactionCommitted::class): void
{
$this->listen($target, function () use ($event): void {
$this->dispatch($event);
});
} Such implementation allow us to dispatch the event with different way in different situation. With your PR if i want to dispatch before transaction is commited i need to create the event object, change his property and after that dispatch it. |
@kafkiansky this has nothing to do with events but rather listeners. |
@themsaid, but... you defined a property inside the event |
@kafkiansky no it's on the listener. |
@themsaid, my mistake, sorry, i have overlooked. but does not matter, it's even worse because you has no way to change this property if need. |
@kafkiansky, as you can see PR uses |
@LastDragon-ru, what problem it solve? This PR add more collisions because in cases when listener implements |
Please see original #35373 issue, if short: class SendWelcomeEmail{
public $disptachAfterCommit = true;
public function handle(){
// ...
}
} much better than: class SendWelcomeEmail{
public function handle(){
DB::afterCommit(function (){
Mail::send(...);
});
}
}
Yep, IMO Laravel should use Container instead of |
Yep, they was mine. And i still confuse why the PR was rejected.
I think, interfaces in this case also is bad idea and even worse than properties. Interface as marker looks bad, sorry. Just use method, why not? Method add more manageable and obvious behavior. |
|
@crnkovic, and what? interfaces in this case make dispatch management more complicated. imagine that you have an listener that trigger when user registration event occur and you have many cases when registration is complete: an api, an web with order issued and without. registration may be too complicated and require transaction, but may be easy and without transaction, but however the event always needs to be dispatch. how you plan change listener behavior? you don't have access to the listener property on runtime. final class RegistrationOccur
{
}
final class RegistrationOccurListener
{
public $disptachAfterCommit = true;
public function when(RegistrationOccur $event) {}
} Complicated registration: $this->connection->transaction(function () {
$user = User::createFromWeb(...);
$order = Order::issue(...);
// other things
$this->dispatcher->dispatch(new RegistrationOccur($user->id));
}); // yeah, property `$disptachAfterCommit` save us from transaction failure! Easy registration: $user = User::createFromApi(...);
$this->dispatcher->dispatch(new RegistrationOccur($user->id)); // hm, where my event??? i lost them, analysts will kill me(( But what about O from SOLID and what about... tests? I have changed value of property public function dispatchAfter(object $event, string $target = TransactionCommitted::class): void
{
$this->listen($target, function () use ($event): void {
$this->dispatch($event); // Or other implementation here.
});
} This method allow to dispatch not after |
If you don't have any transactions, listener will still be dispatched. I agree with the method though. We have a |
Actually, the Dispatcher check and call if present (obviously, it work only for the queued listeners) |
@LastDragon-ru, how you plan to manipulate with listener's method if you don't have access to the listener within dispatch process? conditions to run within transactions or not may be too complicated and depend on code where event is dispatch but not of listener. May be you have code for this cases? |
I don't think that this is the right behavior - in most cases, listeners must be dispatched only if committed. For example: if |
@LastDragon-ru, and i think so: listeners always should be dispatched only if transaction commited, but however for this need individual method because it make behavior more explicit. the listener should not know about such details as transaction life cycle.
No, is boilerplate. |
This PR is similar to #35422. It delays running listeners until transactions commit.
Having a listener to the
UserCreated
event:That listener will not run until after the transaction commits. If the transaction was rolledback, the listener will be discarded.