Skip to content

Race condition when using relation methods #1129

@aadamcik

Description

@aadamcik

Package version

21.8.0

Describe the bug

If you call any relation method multiple times with slight delay, you will get an error with message: Transaction query already complete.

Example

In our case we were fetching an array of photos from remote server and then saving them to database.

class Property extends BaseModel {
  @hasMany(() => PropertyPhoto)
  declare photos: HasMany<typeof PropertyPhoto>
}

class PropertyPhoto extends BaseModel {
  @column()
  declare propertyId: string

  @column()
  declare file: object
}

const photoUrls = extractPhotos() // returns list of urls of photos

await Promise.all(photoUrls.map(async (url) => {
  const file = await savePhotoToDisk(url) // downloads and saves the photo to disk
  
  return await property.related('photos').create({ file })
}))

As soon as there are several photos to save, there is high chance you will get a race condition, because:

  1. Item A before being saved to database will try to create a new transaction.
  2. As soon the A acquires transaction it will set it to parent.$trx.
  3. An insert query will be sent to DB for item A.
  4. Item B will not create a new transaction because parent.$trx is present and use that one.
  5. Item A completes the insert and commit transaction.
  6. Item B will throw error when trying to send INSERT query, because the transaction was closed.

https://github.com/adonisjs/lucid/blob/21.x/src/orm/relations/has_many/query_client.ts#L103

Reproduction: aadamcik@3c3457b

Reproduction repo

aadamcik@3c3457b

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions