rebus-org / Rebus.PostgreSql

:bus: PostgreSQL persistence for Rebus
https://mookid.dk/category/rebus
Other
17 stars 19 forks source link

Rebus.Injection.ResolutionException when multiple clients initialize transport concurrently #46

Closed mastersign closed 1 month ago

mastersign commented 2 months ago

Firstly, I really like Rebus, and especially the PostgreSQL transport, because it allows me to simplify my service infrastructure. I am using it for some years now and had a lot of positive experiences with it.

But now, if I have multiple processes (e. g. 4) initializing the transport concurrently, I sometimes get the following exception. The transport table was already created earlier when I start the processes. This is a bit weird, because normally a create table should fail with relation ... already exists if the table already exists. But the concurrent DDL requests seem to collide somehow in PostgreSQL.

---> Rebus.Injection.ResolutionException: Could not resolve Rebus.Transport.ITransport with decorator depth 0 - registrations: Rebus.Injection.Injectionist+Handler
---> Rebus.Exceptions.RebusApplicationException: Error attempting to initialize SQL transport schema with messages table "public"."transport"
---> Rebus.Exceptions.RebusApplicationException: Error executing SQL command

CREATE TABLE "public"."transport"
(
    id serial NOT NULL,
    recipient text NOT NULL,
    priority int NOT NULL,
    expiration timestamp with time zone NOT NULL,
    visible timestamp with time zone NOT NULL,
    headers bytea NOT NULL,
    body bytea NOT NULL,
    PRIMARY KEY (recipient, priority, id)
);

---> Npgsql.PostgresException (0x80004005): 23505: duplicate key value violates unique constraint "pg_class_relname_nsp_index"

I would like to have an optional parameter automaticallyCreateTables in UsePostgreSql(this StandardConfigurer<ITransport> configurer, ...), to be able to avoid this conflict.

And maybe it would be helpful, if the CREATE TABLE and CREATE INDEX statements in the CreateSchemaAsync() methods would use IF NOT EXISTS. (Supported for CREATE TABLE since PostgreSQL 9.1, and for CREATE INDEX since 9.5`)

If a merge request is appreciated, let me know.

mastersign commented 2 months ago

Found this post related to the issue: https://stackoverflow.com/questions/74261789/postgres-create-table-if-not-exists-%E2%87%92-23505 So the IF NOT EXISTS will probably not help on its own, but the following might.

select pg_advisory_xact_lock(12345);
-- any bigint value, but has to be the same for all parallel sessions
create table if not exists ...;
mookid8000 commented 1 month ago

Rebus.PostgreSql 9.1.1 has retries around all of its schema initialization routines, which should fix this particular issue.

It's on NuGet.org now 🙂

mastersign commented 1 month ago

Thank you! The change in 9.1.1 resolved my issue.