So, it turns out that being stranded in an airport can lead to some productive output after all.
I've hacked together an AMQP extension for PostgreSQL. If you don't know what AMQP or PostgreSQL are, stop reading.
One thing I've needed to do for a while is be able to submit a message to a message queue from within a PostgreSQL transaction. However, obviously (because we run a real database here), if the transaction aborts I'd rather not have those messages sent. Enter pg_amqp.
pg_amqp allows:
- Multiple connections to different AMQP brokers (configured in the amqp.broker table).
- Allows for the declaration of an exchange.
- Tries to be smart about bring up a connection to a broker on demand and leaving it connected to accelerate the next publication request.
- Allows AMQP publishing from within SQL that is transactionally aware (only publishes on commit).
- Allows AMQP publishing from within SQL that is autonomous (happens outside the current transaction).
This is completely alpha. I've tested it quite a bit by hand, but put no load on it whatsoever. Monday of next week, I'm going to beat the ever-living @#$% out of it on one of our systems that desperately needs on-commit AMQP notifications.
I'd love some more eyes on this. It has some flaws, specifically related to processing asynch events from within a PosgreSQL backend (which has no concept of asynchronous even notification). As such, if you do stupid stuff, stupid things happen. The easiest solution is to add a thread to each postgres backend to process the backqueue of events from AMQP; however that so blatantly violates postgres' process model and design that I've no intention to do that. With all the issues aside — it works pretty well for me.
I didn't add queue declaration or the ability to consume from queues. That was intentional because PostgreSQL can't run SQL outside of a transaction block making a while(1) { consume, do, commit } impossible from within SQL itself. Without the ability to do that it seems really useless (and pretty dangerous) to allow someone to do a blocking AMQP frame receive from within SQL. If you think it would be useful for you, let me know — it would be a trivial addition.
Oh yeah: pg_amqp
Sunday, December 20. 2009 at 08:16 (Reply)
Note that sending the message still isn't atomic with the database transaction. If you crash or connection to the queue is broken after the commit record in PostgreSQL has been written to disk, the message is not sent.
Sunday, December 20. 2009 at 08:28 (Reply)
Even more than that. AMQP doesn't really support two-phase commit and it is further compounded by being asynchronous. If AMQP "goes away" after your last publish but before you commit on the postgres side, it will (obviously) not be able to commit to AMQP and PostgreSQL won't know. What's worse is that AMQP is asynchronous so you could think your last publish was success only because the failure notification hasn't made its way back to you — this is also a failure condition.
The one thing that is guaranteed: if you rollback your postgres txn, nothing will go out over AMQP.
BTW, thanks for the tips on where to hook in PostgreSQL.
Sunday, December 20. 2009 at 10:19 (Link) (Reply)
AMQP 0.10 would satisfy all the requirements I have read here: autonomous, distributed (XA) and so forth. No one has finished implementing it yet, but I think they are not too far away.
I would be more than interested in the source as a friend and I have been thinking (and tinkinling) about doing something similar for Oracle Rdb.
Great article, super blog: thank you!
Merry Christmas and a Happy New Year! May you get stuck in more airports...