-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Messenger] Add support for PostgreSQL LISTEN/NOTIFY #35485
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
Conversation
0171724
to
5363561
Compare
src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
Outdated
Show resolved
Hide resolved
An alternative implementation is to use a trigger instead of calling For the record, I first used Edit: implementation added in 5207f51 |
51fc6ee
to
5207f51
Compare
src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
Outdated
Show resolved
Hide resolved
@@ -35,6 +35,9 @@ class Connection | |||
'queue_name' => 'default', | |||
'redeliver_timeout' => 3600, | |||
'auto_setup' => true, | |||
'pgsql_get_notify' => false, |
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 should probably be its own transport, not mixing PostgreSQL-specifics with DBAL abstractions
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 had the same feeling in the beginning, but it will require to duplicate most of the code of this transport. So I'm not sure that it is worth it from a maintenance point of view.
Now that the implementation is less intrusive than it was, I'll check if the PostgreSQL related code can be moved to a decorator.
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.
Yeah, but that's not a big deal: more problematic is having generic SQL and PGSQL mixed within the same service, activated conditionally.
If the "enable norify" logic deals to a completely dedicated adapter, fixing specific bugs and maintenance becomes much easier, and so will debugging 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.
I isolated the PostgresSQL-specific code in a dedicated class, it's a bit cleaner, and while far from being perfect I think it will be good enough for now at least.
src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
Outdated
Show resolved
Hide resolved
@@ -227,6 +270,28 @@ public function setup(): void | |||
$this->driverConnection->getConfiguration()->setFilterSchemaAssetsExpression($assetFilter); | |||
} | |||
|
|||
if ($this->usePgsqlNotify) { | |||
$sql = sprintf(<<<'SQL' |
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.
wrap in begin...commit?
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.
What would be the benefit?
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.
is exec
transactional? you want both statements to fail or both to succeed.
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'm not sure, pg_query
is transnational, but I cannot find the information for exec.
a131f83
to
2be2850
Compare
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.
with minor comment
src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php
Show resolved
Hide resolved
src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php
Show resolved
Hide resolved
a32d12f
to
b976720
Compare
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.
LGTM, minor comment.
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); |
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.
Should be removed
b976720
to
01f33c3
Compare
Thank you @dunglas. |
This PR was merged into the 5.1-dev branch. Discussion ---------- [Messenger] Made final class really final | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | Deprecations? | no | Tickets | | License | MIT | Doc PR | introduced in #35485 (so no BC break) Commits ------- cd8a386 [Messenger] Made final class really final
This PR was merged into the 5.2 branch. Discussion ---------- [Messenger] Don't lock tables or start transactions | Q | A | ------------- | --- | Branch? | 5.2 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | | License | MIT | Doc PR | I was so sure my PR #40336 fixed the doctrine-messenger issue once and for all. But it had a very silent bug.. This has been tricky to debug and find because the `PDO` behaves differently in PHP 7.4 compared to PHP 8. | Scenario | Command | Is executed in transaction | Method that calls `PostgreSqlConnection::getTriggerSql()` | | --| -- | -- | -- | | A | `messenger:setup-transports` | No | `setup()` | B| `doctrine:schema:create` | No | `getExtraSetupSqlForTable()` | C | `doctrine:migration:diff` | Yes by default, but it can be configured | `getExtraSetupSqlForTable()` PR #40055 fixed scenario C on PHP 8, but that also broke scenario B on PHP 7.4 and PHP 8. In PR #40336 I was wrong claiming: > We don't need COMMIT because the transaction will commit itself when we close the connection. The result was the we removed all the errors messages from the 3 scenarios. But scenario B will produce some SQL that is actually never committed. IE it will silently fail. I've been trying to figure out a good solution to how or when to start a transaction. I tried out @fbourigault [suggestion](#40336 (comment)) but that would be the same fix as #40055. --------------- We need a transaction because the SQL includes a `LOCK TABLE`, however, I cannot see a strict need for it. This PR removes `LOCK TABLE` and all transaction juggling. It all seams to work. I would be happy to get thorough feedback on this PR so we can end the chapter of constantly adding bugs to this part of the component. @dunglas, you added `LOCK TABLE` in your initial version of this class in #35485, could you share some knowledge if this is a good or bad idea? Commits ------- 26061a1 Dont lock tables or start transactions
…upport (t-richard) This PR was squashed before being merged into the 5.2 branch. Discussion ---------- [Messenger] Add options for PostgreSQL LISTEN/NOTIFY support <!-- If your pull request fixes a BUG, use the oldest maintained branch that contains the bug (see https://symfony.com/releases for the list of maintained branches). If your pull request documents a NEW FEATURE, use the same Symfony branch where the feature was introduced (and `5.x` for features of unreleased versions). --> Documents symfony/symfony#35485 Closes #13039 Commits ------- 55edd48 [Messenger] Add options for PostgreSQL LISTEN/NOTIFY support
PostgreSQL comes with a builtin, performant, scalable and transactional pub/sub system called
LISTEN
/NOTIFY
.This PR allows to leverage this mechanism when using the Messenger component with Postgres.
When the Postgres is used, workers are notified in real-time when a message is dispatched.
This reduces the latency, and prevents the worker from executing useless SQL queries. Basically, it allows to switch from a polling-based approach to an event-based one.
This patch can be used with all existing installation of Messenger, as long as the underlying DBMS is Postgres. For many (most ?) projects, it allows to get the benefits of using a queue system such as RabbitMQ or Pulsar without having to introduce new services to monitor, replicate or upgrade.
If PostgreSQL is used,
LISTEN
/NOTIFY
is used automatically!That's all!
It's also possible to configure how long the worker must wait for new messages:
Then you can use start the workers with something like:
php bin/console messenger:consume --sleep=0
A demo app using this new feature is available in this repository: https://github.com/dunglas/demo-postgres-listen-notify
TODO: