Skip to content

Hang-up with relationLoadStrategy: query for Multiple Calls #10481

@saw81wt

Description

@saw81wt

Issue description

Using relationLoadStrategy set to "query" may result in a hang-up.

Expected Behavior

When calling the find method with relationLoadStrategy set to "query" on tables with 1:N relationships, the process completes successfully.

Actual Behavior

When multiple find method calls are made simultaneously with this setting, the system fails to complete the process and experiences a hang-up.

Steps to reproduce

Entities

We have tables with 1:N relationships.

import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm"
import { Photo } from "./Photo"

@Entity()
export class User {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    name: string

    @OneToMany(() => Photo, (photo) => photo.user, { eager: false })
    photos: Photo[]
}
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm"
import { User } from "./User"

@Entity()
export class Photo {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    url: string

    @ManyToOne(() => User, (user) => user.photos)
    user: User
}

Bussiness Code

In our business code, we make simultaneous calls using the find method that includes relationships, setting the relationLoadStrategy to 'query'.

import { AppDataSource } from "../typeorm/data-source"
import { User } from "../typeorm/entity/User"

const main = async () => {
    await AppDataSource.initialize()
    const findUserWithPhoto = async () => {
        const repository = AppDataSource.getRepository(User)
        return await repository.findOne({
            where: { id: 1 },
            relations: {
                photos: true
            },
            relationLoadStrategy: "query"
        })
    }

    const result = []
    for (let i = 0; i < 10; i++) {
        result.push(findUserWithPhoto())
    }
    await Promise.all(result)
    await AppDataSource.destroy()
}

main()

For reproduction purposes, we are making multiple calls using a for loop. However, the same issue arises when server-side endpoints are rapidly and simultaneously accessed by clients

My Environment

Dependency Version
Operating System
Node.js version 18.y.zzz
Typescript version 5.2.2
TypeORM version 0.3.16

Additional Context

probably the cause

In TypeORM, the obtainQueryRunner() is used to acquire a connection. However, the issue here is that this.queryRunner is set with a value only in certain cases, which leads to the system consistently evaluating the right-hand expression of obtainQueryRunner.

In the connection pool, if no connections are available, the system waits until a new connection is released. If obtainQueryRunner is called multiple times within the queryRunner, there is a potential for a deadlock to occur between the release of a connection and the acquisition of a new one. This deadlock can cause the system to become unresponsive or hang.

reproduction code

https://github.com/saw81wt/typeorm-hung-up/tree/master

Relevant Database Driver(s)

  • aurora-mysql
  • aurora-postgres
  • better-sqlite3
  • cockroachdb
  • cordova
  • expo
  • mongodb
  • mysql
  • nativescript
  • oracle
  • postgres
  • react-native
  • sap
  • spanner
  • sqlite
  • sqlite-abstract
  • sqljs
  • sqlserver

Are you willing to resolve this issue by submitting a Pull Request?

No, I don’t have the time, but I can support (using donations) development.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions