Skip to content

Commit a53f2a9

Browse files
authored
feature: postgresql symfony messenger bridge (#2298)
- added postgresql symfony messenger bridge - added listen/unlisen to postgresql client - added postgresql symfony messenger bridge to postgersql symfony bundle
1 parent de0602d commit a53f2a9

83 files changed

Lines changed: 3967 additions & 67 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codecov.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ component_management:
108108
name: bridge-symfony-postgresql-bundle
109109
paths:
110110
- src/bridge/symfony/postgresql-bundle/**
111+
- component_id: bridge-symfony-postgresql-messenger
112+
name: bridge-symfony-postgresql-messenger
113+
paths:
114+
- src/bridge/symfony/postgresql-messenger/**
111115
- component_id: bridge-symfony-telemetry-bundle
112116
name: bridge-symfony-telemetry-bundle
113117
paths:

.github/workflows/monorepo-split.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ jobs:
9898
split_repository: 'symfony-http-foundation-telemetry-bridge'
9999
- local_path: 'src/bridge/symfony/postgresql-bundle'
100100
split_repository: 'symfony-postgresql-bundle'
101+
- local_path: 'src/bridge/symfony/postgresql-messenger'
102+
split_repository: 'symfony-postgresql-messenger-bridge'
101103
- local_path: 'src/bridge/symfony/telemetry-bundle'
102104
split_repository: 'symfony-telemetry-bundle'
103105
- local_path: 'src/bridge/telemetry/otlp'

.nix/php/lib/php.ini.dist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ upload_max_filesize = 150M
88
file_uploads = On
99
max_file_uploads = 20
1010
short_open_tag = off
11+
opcache.enable=1
12+
opcache.enable_cli=0

composer.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
"flow-php/symfony-http-foundation-bridge": "self.version",
112112
"flow-php/symfony-http-foundation-telemetry-bridge": "self.version",
113113
"flow-php/symfony-postgresql-bundle": "self.version",
114+
"flow-php/symfony-postgresql-messenger-bridge": "self.version",
114115
"flow-php/symfony-telemetry-bundle": "self.version",
115116
"flow-php/telemetry": "self.version",
116117
"flow-php/telemetry-otlp-bridge": "self.version",
@@ -148,6 +149,7 @@
148149
"src/bridge/symfony/http-foundation-telemetry/src/Flow",
149150
"src/bridge/symfony/http-foundation/src/Flow",
150151
"src/bridge/symfony/postgresql-bundle/src/Flow",
152+
"src/bridge/symfony/postgresql-messenger/src/Flow",
151153
"src/bridge/symfony/telemetry-bundle/src/Flow",
152154
"src/bridge/telemetry/otlp/src/Flow",
153155
"src/bridge/phpunit/telemetry/src/Flow",
@@ -248,6 +250,7 @@
248250
"src/bridge/symfony/http-foundation-telemetry/tests/Flow",
249251
"src/bridge/symfony/http-foundation/tests/Flow",
250252
"src/bridge/symfony/postgresql-bundle/tests/Flow",
253+
"src/bridge/symfony/postgresql-messenger/tests/Flow",
251254
"src/bridge/symfony/telemetry-bundle/tests/Flow",
252255
"src/bridge/telemetry/otlp/tests/Flow",
253256
"src/bridge/phpunit/telemetry/tests/Flow",
@@ -325,6 +328,7 @@
325328
"@test:bridge:symfony-http-foundation",
326329
"@test:bridge:symfony-http-foundation-telemetry",
327330
"@test:bridge:symfony-postgresql-bundle",
331+
"@test:bridge:symfony-postgresql-messenger",
328332
"@test:bridge:symfony-telemetry-bundle",
329333
"@test:bridge:telemetry-otlp"
330334
],
@@ -430,6 +434,10 @@
430434
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-bundle-unit --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-bundle-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-bundle-unit.coverage.xml",
431435
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-bundle-integration --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-bundle-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-bundle-integration.coverage.xml"
432436
],
437+
"test:bridge:symfony-postgresql-messenger": [
438+
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-messenger-unit --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-messenger-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-messenger-unit.coverage.xml",
439+
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-messenger-integration --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-messenger-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-messenger-integration.coverage.xml"
440+
],
433441
"test:bridge:symfony-telemetry-bundle": [
434442
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-telemetry-bundle-unit --log-junit ./var/phpunit/logs/bridge-symfony-telemetry-bundle-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-telemetry-bundle-unit.coverage.xml",
435443
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-telemetry-bundle-integration --log-junit ./var/phpunit/logs/bridge-symfony-telemetry-bundle-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-telemetry-bundle-integration.coverage.xml"

documentation/components/bridges/symfony-postgresql-bundle.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,65 @@ Target a specific connection with any command:
299299
php bin/console flow:migrations:migrate --connection=reporting
300300
```
301301

302+
## Symfony Messenger Integration
303+
304+
The bundle integrates with [flow-php/symfony-postgresql-messenger-bridge](/documentation/components/bridges/symfony-postgresql-messenger-bridge.md) to provide a Symfony Messenger transport backed by Flow's native PostgreSQL client — no Doctrine DBAL required.
305+
306+
### Setup
307+
308+
1. Install the messenger bridge:
309+
310+
```bash
311+
composer require flow-php/symfony-postgresql-messenger-bridge:~--FLOW_PHP_VERSION--
312+
```
313+
314+
2. Enable messenger:
315+
316+
```yaml
317+
flow_postgresql:
318+
connections:
319+
default:
320+
dsn: '%env(DATABASE_URL)%'
321+
322+
messenger:
323+
enabled: true
324+
table_name: messenger_messages # default
325+
schema: public # default
326+
```
327+
328+
3. Configure the Symfony Messenger transport:
329+
330+
```yaml
331+
# config/packages/messenger.yaml
332+
framework:
333+
messenger:
334+
transports:
335+
async:
336+
dsn: 'flow-pgsql://default'
337+
routing:
338+
App\Message\MyMessage: async
339+
```
340+
341+
4. Generate and run the migration to create the messenger table:
342+
343+
```bash
344+
php bin/console flow:migrations:diff
345+
php bin/console flow:migrations:migrate
346+
```
347+
348+
The `MessengerCatalogProvider` is registered automatically when `messenger.enabled: true`, so the `messenger_messages` table appears in schema diffs alongside your other catalog-managed tables.
349+
350+
### Configuration Options
351+
352+
| Option | Default | Location | Description |
353+
|--------|---------|----------|-------------|
354+
| `table_name` | `messenger_messages` | `flow_postgresql.messenger` | Table name in the database |
355+
| `schema` | `public` | `flow_postgresql.messenger` | Schema owning the table |
356+
| `queue_name` | `default` | `framework.messenger.transports.*.options` | Queue name for message routing |
357+
| `redeliver_timeout` | `3600` | `framework.messenger.transports.*.options` | Seconds before unacknowledged messages are redelivered |
358+
359+
For full documentation, see the [Symfony PostgreSQL Messenger Bridge](/documentation/components/bridges/symfony-postgresql-messenger-bridge.md).
360+
302361
## Complete Example
303362

304363
```yaml
@@ -316,6 +375,9 @@ flow_postgresql:
316375
log_queries: false
317376
max_query_length: 1000
318377
378+
messenger:
379+
enabled: true
380+
319381
migrations:
320382
enabled: true
321383
directory: "%kernel.project_dir%/migrations"
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Symfony PostgreSQL Messenger Bridge
2+
3+
A Symfony Messenger transport backed by Flow PHP's native PostgreSQL library. Replaces `symfony/doctrine-messenger` without requiring Doctrine DBAL — messages are stored directly in PostgreSQL using Flow's query builder and client.
4+
5+
- [Back](/documentation/introduction.md)
6+
- [Packagist](https://packagist.org/packages/flow-php/symfony-postgresql-messenger-bridge)
7+
- [GitHub](https://github.com/flow-php/symfony-postgresql-messenger-bridge)
8+
- [API Reference](/documentation/api/bridge/symfony-postgresql-messenger)
9+
10+
[TOC]
11+
12+
## Installation
13+
14+
```bash
15+
composer require flow-php/symfony-postgresql-messenger-bridge:~--FLOW_PHP_VERSION--
16+
```
17+
18+
This package is used together with the [Symfony PostgreSQL Bundle](/documentation/components/bridges/symfony-postgresql-bundle.md), which registers the transport factory and catalog provider automatically.
19+
20+
## How It Works
21+
22+
The bridge provides a Symfony Messenger transport that stores messages in a PostgreSQL table using Flow's native `Client`. No Doctrine DBAL is involved.
23+
24+
- **Sending** inserts a row with `body`, `headers`, `queue_name`, `created_at`, and `available_at`
25+
- **Receiving** uses `SELECT ... FOR UPDATE SKIP LOCKED` inside a transaction for safe concurrent consumption
26+
- **Delayed messages** offset `available_at` by the `DelayStamp` value (in milliseconds)
27+
- **Redelivery** of timed-out messages is handled automatically based on `redeliver_timeout`
28+
- **Keepalive** refreshes `delivered_at` to prevent redelivery during long-running handlers
29+
30+
## Configuration
31+
32+
### 1. Enable Messenger
33+
34+
In your `flow_postgresql` configuration, enable messenger at the root level:
35+
36+
```yaml
37+
# config/packages/flow_postgresql.yaml
38+
flow_postgresql:
39+
connections:
40+
default:
41+
dsn: '%env(DATABASE_URL)%'
42+
43+
messenger:
44+
enabled: true
45+
table_name: messenger_messages # default
46+
schema: public # default
47+
```
48+
49+
This registers a `MessengerCatalogProvider` and a transport factory that can resolve any configured connection by name. The `messenger_messages` table will be included in schema diffs and migrations automatically.
50+
51+
### 2. Configure the Messenger Transport
52+
53+
```yaml
54+
# config/packages/messenger.yaml
55+
framework:
56+
messenger:
57+
transports:
58+
async:
59+
dsn: 'flow-pgsql://default'
60+
options:
61+
queue_name: default # default
62+
redeliver_timeout: 3600 # seconds, default
63+
routing:
64+
App\Message\MyMessage: async
65+
```
66+
67+
The DSN format is `flow-pgsql://<connection_name>` where `<connection_name>` matches a connection defined under `flow_postgresql.connections`. Both `flow-pgsql://` and `flow-postgresql://` schemes are supported.
68+
69+
### 3. Create the Table via Migrations
70+
71+
Because the catalog provider is registered automatically, the messenger table appears in migration diffs:
72+
73+
```bash
74+
php bin/console flow:migrations:diff
75+
php bin/console flow:migrations:migrate
76+
```
77+
78+
This is the recommended approach. The bridge does **not** implement `SetupableTransportInterface` — there is no `messenger:setup-transports` support. Use migrations for schema management.
79+
80+
## DSN Options
81+
82+
Options can be set in the DSN query string or in the `options` array under the transport configuration. The `options` array takes precedence over DSN query parameters.
83+
84+
| Option | Default | Description |
85+
|--------|---------|-------------|
86+
| `queue_name` | `default` | Queue name for message routing |
87+
| `table_name` | `messenger_messages` | Table storing messages (must match `flow_postgresql.messenger` config) |
88+
| `schema` | `public` | Schema owning the table (must match `flow_postgresql.messenger` config) |
89+
| `redeliver_timeout` | `3600` | Seconds before a delivered-but-unacknowledged message becomes eligible for redelivery |
90+
91+
Example with DSN options:
92+
93+
```yaml
94+
framework:
95+
messenger:
96+
transports:
97+
high_priority:
98+
dsn: 'flow-pgsql://default?queue_name=high&redeliver_timeout=1800'
99+
```
100+
101+
## Multiple Queues
102+
103+
Multiple transports can share the same table but use different queue names:
104+
105+
```yaml
106+
framework:
107+
messenger:
108+
transports:
109+
async:
110+
dsn: 'flow-pgsql://default'
111+
options:
112+
queue_name: default
113+
high_priority:
114+
dsn: 'flow-pgsql://default'
115+
options:
116+
queue_name: high
117+
routing:
118+
App\Message\ImportantMessage: high_priority
119+
App\Message\BackgroundTask: async
120+
```
121+
122+
## Table Schema
123+
124+
The messenger table has the following structure:
125+
126+
| Column | Type | Description |
127+
|--------|------|-------------|
128+
| `id` | `bigint GENERATED ALWAYS AS IDENTITY` | Primary key |
129+
| `body` | `text` | Serialized message body |
130+
| `headers` | `text` | JSON-encoded message headers (stamps, type info) |
131+
| `queue_name` | `varchar(190)` | Queue name for message routing |
132+
| `created_at` | `timestamptz` | When the message was dispatched |
133+
| `available_at` | `timestamptz` | When the message becomes available for consumption |
134+
| `delivered_at` | `timestamptz` | When a worker picked up the message (null = not yet delivered) |
135+
136+
Three indexes are created: on `queue_name`, `available_at`, and `delivered_at`.

documentation/installation/packages/symfony-postgresql-bundle.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@ composer require flow-php/symfony-postgresql-bundle:~--FLOW_PHP_VERSION--
3636

3737
## Suggested Dependencies
3838

39+
- [flow-php/symfony-postgresql-messenger-bridge](/documentation/installation/packages/symfony-postgresql-messenger-bridge.md) — for Symfony Messenger PostgreSQL transport support (replaces `symfony/doctrine-messenger`)
3940
- [flow-php/symfony-telemetry-bundle](/documentation/installation/packages/symfony-telemetry-bundle.md) — for telemetry integration (distributed tracing, metrics, logging)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
seo_title: "Installing Symfony PostgreSQL Messenger Bridge"
3+
seo_description: >
4+
How to install flow-php/symfony-postgresql-messenger-bridge in your PHP project using Composer.
5+
---
6+
7+
# Symfony PostgreSQL Messenger Bridge
8+
9+
- [Back](/documentation/installation.md)
10+
- [Documentation](/documentation/components/bridges/symfony-postgresql-messenger-bridge.md)
11+
- [Packagist](https://packagist.org/packages/flow-php/symfony-postgresql-messenger-bridge)
12+
13+
[TOC]
14+
15+
## Composer
16+
17+
```bash
18+
composer require flow-php/symfony-postgresql-messenger-bridge:~--FLOW_PHP_VERSION--
19+
```
20+
21+
## Core Dependencies
22+
23+
- [flow-php/postgresql](/documentation/installation/packages/postgresql.md)
24+
- [symfony/messenger](https://packagist.org/packages/symfony/messenger)
25+
26+
## Recommended Packages
27+
28+
- [flow-php/symfony-postgresql-bundle](/documentation/installation/packages/symfony-postgresql-bundle.md) — registers the transport factory and catalog provider automatically via Symfony bundle configuration
29+
30+
## Recommended Extensions
31+
32+
- `ext-pgsql` — required for database connections and query execution

manifest.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@
191191
"path": "src/bridge/symfony/postgresql-bundle",
192192
"type": "bridge"
193193
},
194+
{
195+
"name": "flow-php/symfony-postgresql-messenger-bridge",
196+
"path": "src/bridge/symfony/postgresql-messenger",
197+
"type": "bridge"
198+
},
194199
{
195200
"name": "flow-php/symfony-telemetry-bundle",
196201
"path": "src/bridge/symfony/telemetry-bundle",
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<phpdocumentor
3+
configVersion="3"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns="https://www.phpdoc.org"
6+
>
7+
<title>Flow PHP</title>
8+
<paths>
9+
<output>./../web/landing/build/documentation/api/bridge/symfony/postgresql-messenger</output>
10+
<cache>./../var/phpdocumentor/cache/bridge/symfony/postgresql-messenger</cache>
11+
</paths>
12+
<version number="1.x">
13+
<api format="php">
14+
<source dsn="./../">
15+
<path>src/bridge/symfony/postgresql-messenger/src</path>
16+
</source>
17+
<output>symfony-postgresql-messenger</output>
18+
<default-package-name>Symfony PostgreSQL Messenger</default-package-name>
19+
<visibility>public</visibility>
20+
<include-source>false</include-source>
21+
</api>
22+
</version>
23+
<setting name="template.color" value="orange"/>
24+
</phpdocumentor>

0 commit comments

Comments
 (0)