You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm working on a watermill integration using Postgres with the following schema:
CREATETABLEIF NOT EXISTS public.watermill_example
(
"offset"bigintNOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
uuid character varying(36) COLLATE pg_catalog."default"NOT NULL,
created_at timestamp without time zoneNOT NULL DEFAULT now(),
payload bytea,
metadata bytea,
transaction_id xid8 NOT NULL,
CONSTRAINT watermill_example_pkey PRIMARY KEY ("offset", transaction_id)
)
CREATETABLEIF NOT EXISTS public.watermill_offsets_example
(
consumer_group character varying(255) COLLATE pg_catalog."default"NOT NULL,
offset_acked bigint,
last_processed_transaction_id xid8 NOT NULL,
CONSTRAINT watermill_offsets_example_pkey PRIMARY KEY (consumer_group)
)
However after a message is consumed the first time, the logs are full of errors when trying to ACK the success
[watermill] 2024/12/21 00:27:19.044828 subscriber.go:435: level=DEBUG msg="Message acked by subscriber" consumer_group=api err="could not get args for acking the message: ERROR: column "last_processed_transaction_id" is of type xid8 but expression is of type integer (SQLSTATE 42804)" msg_uuid=0c5c5b21-e92f-4176-a1a9-bcf4b3358a9d subscriber_id=01JFK9CZVXSFRWT7V4Z1EMWWXQ topic=example
[watermill] 2024/12/21 00:27:19.045498 backoff_manager.go:58: level=ERROR msg="Error querying for message" consumer_group=api err="could not get args for acking the message: ERROR: column "last_processed_transaction_id" is of type xid8 but expression is of type integer (SQLSTATE 42804)" subscriber_id=01JFK9CZVXSFRWT7V4Z1EMWWXQ topic=examplewait_time=1s
The code is fairly standard from what I could tell in the docs:
funcsetupPubSub(db*gorm.DB, logger watermill.LoggerAdapter) (*sql.Publisher, *sql.Subscriber) {
stdLibSqlDB, err:=db.DB()
iferr!=nil {
panic(err)
}
deadline:=time.Minute*30sub, err:=sql.NewSubscriber(
stdLibSqlDB,
sql.SubscriberConfig{
ConsumerGroup: "api",
SchemaAdapter: sql.DefaultPostgreSQLSchema{},
OffsetsAdapter: sql.DefaultPostgreSQLOffsetsAdapter{},
ResendInterval: time.Minute*5,
AckDeadline: &deadline,
},
logger,
)
iferr!=nil {
panic(err)
}
pub, err:=sql.NewPublisher(
stdLibSqlDB,
sql.PublisherConfig{
SchemaAdapter: sql.DefaultPostgreSQLSchema{},
},
logger,
)
iferr!=nil {
panic(err)
}
returnpub, sub
}
funcsetupWatermillRouter(logger watermill.LoggerAdapter) (*message.Router, error) {
router, err:=message.NewRouter(message.RouterConfig{}, logger)
iferr!=nil {
log.Println(fmt.Errorf("Error creating eventing router: %w", err))
}
// SignalsHandler will gracefully shutdown Router when SIGTERM is received.// You can also close the router by just calling `r.Close()`.router.AddPlugin(plugin.SignalsHandler)
// Router level middleware are executed for every message sent to the routerrouter.AddMiddleware(
(&middleware.Deduplicator{
Timeout: time.Minute*30,
}).Middleware,
// CorrelationID will copy the correlation id from the incoming message's metadata to the produced messagesmiddleware.CorrelationID,
// The handler function is retried if it returns an error.// After MaxRetries, the message is Nacked and it's up to the PubSub to resend it.
middleware.Retry{
MaxRetries: 3,
InitialInterval: time.Millisecond*100,
RandomizationFactor: 2.5,
Logger: logger,
}.Middleware,
// Recoverer handles panics from handlers.// In this case, it passes them as errors to the Retry middleware.middleware.Recoverer,
)
returnrouter, err
}
funcmain() {
// ... snip some gorm DB connectionlogger:=watermill.NewStdLogger(true, false)
router, err:=setupWatermillRouter(logger)
iferr!=nil {
log.Fatalln(err)
}
pub, sub:=setupPubSub(db, logger)
// Register handlers// ... snip
}
This error makes sense to me as the Go SQL driver will try to write the transaction_id as an integer, which is not supported in Postgres into an xid8 column. Hence this workaround "solves" the issue but results in two casts
func (aOffsetsAdapter) AckMessageQuery(topicstring, row sql.Row, consumerGroupstring) sql.Query {
ackQuery:=`INSERT INTO `+a.MessagesOffsetsTable(topic) +`(offset_acked, last_processed_transaction_id, consumer_group) VALUES ($1, $2::text::xid8, $3) -- THIS IS THE LINE THAT IS CHANGED ON CONFLICT (consumer_group) DO UPDATE SET offset_acked = excluded.offset_acked, last_processed_transaction_id = excluded.last_processed_transaction_id`return sql.Query{ackQuery, []any{row.Offset, row.ExtraData["transaction_id"], consumerGroup}}
}
So I guess my question is, how does this normally work? This is with Postgres 15.
The text was updated successfully, but these errors were encountered:
I'm working on a watermill integration using Postgres with the following schema:
However after a message is consumed the first time, the logs are full of errors when trying to ACK the success
The code is fairly standard from what I could tell in the docs:
This error makes sense to me as the Go SQL driver will try to write the transaction_id as an integer, which is not supported in Postgres into an xid8 column. Hence this workaround "solves" the issue but results in two casts
So I guess my question is, how does this normally work? This is with Postgres 15.
The text was updated successfully, but these errors were encountered: