Skip to content

Commit 5d97c43

Browse files
committed
Use one commit for the dimensions upsert
Flush+commit (1 transaction) instead of two commits (2 transactions) to make this atomic. If two identical dimensions update jobs are picked up by two different workers, there could a potential concurrency issue. The first upsert has postgres row locks with on_conflict_do_update and should be fine, but the FK table update added in #70 was a second transaction without row lock. In the previous CRUD, there was a window between the first and second transactions where another concurrent identical job could see the first transaction (parent row with updated counts) but see that the child tables would be empty and re-calculate the scaffolds and samples. This was not a breaking concurrency issue (no data corruption), but an inefficient one that could cause redundant work.
1 parent 183f4f9 commit 5d97c43

1 file changed

Lines changed: 7 additions & 1 deletion

File tree

packages/divbase-api/src/divbase_api/worker/crud_dimensions.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,19 @@ def create_or_update_vcf_metadata(db: Session, vcf_metadata_data: VCFMetadataDat
133133
)
134134

135135
db.execute(stmt)
136-
db.commit()
136+
137+
# Flush instead of commit here so that the INSERT/UPDATE is visible to get_vcf_metadata_by_keys below.
138+
# The flush will be visible to other operations within the same db session, but will not yet be committed to the database (invisivle to other db sessions).
139+
# This avoids concurrency issues for the child tables if two identical dimensions update jobs are run concurrently in the job system.
140+
db.flush()
137141

138142
# Get the upserted/updated entry from the main model (=parent object) and use it to add the samples and scaffolds to the respective FK tables (=child objects)
139143
vcf_metadata = get_vcf_metadata_by_keys(db, vcf_metadata_data.vcf_file_s3_key, vcf_metadata_data.project_id)
140144
# Important! This is a full replacement based on the VCF files in the bucket, not an append. If a samples in a vcf file is added, changed, or removed, the relationship will delete the existing samples entries for that VCF with cascade="all, delete-orphan" and insert the new ones.
141145
vcf_metadata.samples = [VCFMetadataSamplesDB(sample_name=name) for name in samples]
142146
vcf_metadata.scaffolds = [VCFMetadataScaffoldsDB(scaffold_name=name) for name in scaffolds]
147+
148+
# Single commit for parent upsert and child table updates.
143149
db.commit()
144150

145151
logger.info(

0 commit comments

Comments
 (0)