Skip to content

Concurrency *within* transactions. #507

@jonathanstowe

Description

@jonathanstowe

I think that the following may just be a very strong warning in the documentation as I can't actually think of a sane way of fixing it, though your mileage may vary.

Consider some code that does something like:

red-do {

# do something to DB

start {
   # do something to do DB
};

# do something to DB
}, :transaction;

With the Pg driver, the #504 essentially isolates a transaction from other concurrent access outside the transaction by creating a new instance of DB::Pg with its own connection pool such that as long as all access in the transaction is performed sequentially then all will get the same underlying connection from the pool.

However if some code is started asynchronously as above, the async code will get the existing DB::Pg::Database instance (assumed to be the one that the transaction was started on,) at which point it essentially becomes a race between the async code, any DB code after it is started and crucially the COMMIT (or ROLLBACK ) which may get a different connection from the pool such that the code after may not be in the transaction, or the commit is called on a connection without a transaction (leading to an error.) Obviously it becomes less predictable if more threads are spawned.

The only way to prevent this is by waiting on the async code before any further DB access is done in the main block and especially before the end of the red-do block.

A mitigation could be provided if the async code doesn't need to take part in the main transaction by allowing a red-do to over-ride the behaviour described in #506 and force the creation of a further new driver instance with a new connection. But :-(

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions