Cross DB modifications in Ci::Build within state transitions

What is a cross-database modification

Cross-database modification happens when data is modified in two different databases within an open transaction. This can cause reliability issues later when the CI database tables are moved to a separate database server.

Example: keeping transaction open to wait for a 3rd party call (UPDATE query in a different DB) which cannot be rolled back anyway.

Problem

The Ci::Build model implements a state machine where various state transitions alter the associated deployment record.

Offenses

The Offenses have been ignored with the .allow_cross_database_modification_within_transaction method. You can find them by grepping for the method name and the issue number:

grep -n "allow_cross_database_modification_within_transaction.*338867" app/models/ci/build.rb

See an example here: https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/ci/build.rb#L333

You can remove the allow_cross_database_modification_within_transaction block and run the test cases to see the actual failure messages. (rspec spec/models/ci/build_spec.rb)

Once the offenses have been fixed the allow_cross_database_modification_within_transaction method calls can be removed and this issue can be closed.

Proposal

The deployments table will stay in the Main database so the update statements need to be moved out of the state machine's transaction.

Options:

  • Use the build.run_after_commit block.
  • Use an async job to make the record updates.

Both options are less "safe". We're not going to have the same consistency guarantee as to the version with the transaction so we need to find the best way forward. Let's discuss ideas and the trade-offs in the comment section.

Edited by Adam Hegyi