blehnen / DotNetWorkQueue

A work queue for dot.net with SQL server, SQLite, Redis and PostGreSQL backends

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Question: Transactions

dazinator opened this issue · comments

Hi,

I was looking into a scenario where we want to save a record to our sql database, but then trigger a bunch of plugins that are interested into responding when that event has taken place.

My thoughts are to save the record to the database, and then write a message to the queue in a single transaction. I can then write the logic to dequeue the message and fire the plugins, and only remove the event from the queue once all the plugins have responded. Plugins will be written to handle the message idempotently.

This idea behind this is to avoid a scenario in which we have saved the record to the database but then the application dies, before a message can be written to the queue, and therefore plugins are never notified of the event.

With this in mind, is it possible to use the sql server transport with an existing transaction? For example if I was using EFCore to save a record I'd want to save that and push the message to the queue using the same DbConnection and a transaction for this to work.

Thanks

Are you trying to use a single transaction for both the enqueue and the dequeue? Or just the dequeue? The queue - for better or worse - will enlist in distributed transactions, as that's the default behavior in the MS driver. That being said, that's not really a workflow that I've tried or tested.

You can tell the SQL transport consumer to keep the transaction open for the entire duration of message processing; That's going to have performance impact on your SQL server if the message is long running.

The setting name is 'EnableHoldTransactionUntilMessageCommitted' on the options class and is false by default.

Are you trying to use a single transaction for both the enqueue and the dequeue

No, I only want to enqueue a message in a transaction - with some other of my own Sql operations participating. The dequeue / consumers don't need to participate.

While there is nothing in the producer that would explicitly support this, you can try wrapping your logic and the message enqueue into a transaction scope -

using (var ts=new TransactionScope())
{
//perform all work inside the scope, including queuing the message
//...
ts.Complete(); //only if everything completed
}