-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Messenger] DoctrineTransport: ensure auto setup is only done once #32308
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
[Messenger] DoctrineTransport: ensure auto setup is only done once #32308
Conversation
@@ -134,7 +136,7 @@ public function send(string $body, array $headers, int $delay = 0): string | ||
|
||
public function get(): ?array | ||
{ | ||
if ($this->configuration['auto_setup']) { | ||
if ($this->autoSetup) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should add a comment here:
// manually try to setup because the transaction below prevents setup on failure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, or I have a different idea. The truly desired behavior is to only setup once we know that the table is actually missing. That's how it's done on every other method... we just can't do it here because of the transaction.
Could we instead do this:
- Don't do any "setup" here - so, make it like all the other methods
- In
executeQuery()
, tweak the logic a little bit inside the} catch (TableNotFoundException $e) {
. Specifically, if we are in a transaction, immediately re-throw theTableNotFoundException
. Otherwise, do the current logic of setting up and trying again. - In
get()
, in thecatch()
, if the exception is aTableNotFoundException
, rollback() (like normal), but then setup and then try the entireget()
method again (probably we'll need to extra the majority ofget()
- the part inside thetry
to a private function so it can be called both in the try and again in the catch).
@vincenttouzet WDYT? By the way, see #32712 where a related conversation (for different reasons) is happening around AMQP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@weaverryan I like the idea. This way the setup would only be run once for ALL workers. For now it runs at the first get
for each worker (if the auto_setup
is configured to true)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bendavies we have some consensus - could you try to put this into your PR? thx :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@weaverryan sounds good. bit busy this week but can take a look after that. if you want to go ahead without me, feel free.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that we should be able to implement this like ryan suggested. @bendavies do you have time to finish this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot about this. I'll look to do it next week.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@weaverryan better late than never. take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
be careful about doing a setup inside a transaction. In some platforms (MySQL being one of them), doing a DDL statement in a transaction will commit the existing transaction and start a new one after, so a rollback later will rollback only until your DDL statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stof it seems that is explicitly checked for now and handled, isn't it?
@vincenttouzet I'd like your eyes on this too :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great - we setup lazily in executeQuery()
in all cases. And for the one "transaction" case in get()
, we handle it manually.
The Connection was only ever written the "incorrect" way because we were imitating the logic from Amqp, where the connection setup is cheap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, but AppVeyor test failure does look related
fixed? |
failure unrelated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php
Show resolved
Hide resolved
This should be ready to go! |
Thank you @bendavies. |
…one once (bendavies) This PR was squashed before being merged into the 4.3 branch (closes #32308). Discussion ---------- [Messenger] DoctrineTransport: ensure auto setup is only done once | Q | A | ------------- | --- | Branch? | 4.3 | Bug fix? | yes | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? |no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #... <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> Setup is done for every invocation of `get`, `find`, and `findAll`. For `get`, this causes message consumption to be very slow, as slow as 1 message per second on my moderately sized schema, because a schema diff is done in `setup` every `get`. I'm not sure what the desired behaviour is here, but it seems like we should try performing a query, fail once, `setup`, and retry. This will the same approach taken by the PDO Cache. However, we still need auto setup in `get`, as `get` starts a transaction, so the auto setup in `executeQuery` won't be called. Further more, the same problem seems to exist for the AMPQ Transport, but the performance impact should be less there, but i have not tried. Commits ------- 0241402 [Messenger] DoctrineTransport: ensure auto setup is only done once
Setup is done for every invocation of
get
,find
, andfindAll
.For
get
, this causes message consumption to be very slow, as slow as 1 message per second on my moderately sized schema, because a schema diff is done insetup
everyget
.I'm not sure what the desired behaviour is here, but it seems like we should try performing a query, fail once,
setup
, and retry. This will the same approach taken by the PDO Cache.However, we still need auto setup in
get
, asget
starts a transaction, so the auto setup inexecuteQuery
won't be called.Further more, the same problem seems to exist for the AMPQ Transport, but the performance impact should be less there, but i have not tried.