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

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions