-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stream() bug from 0.2.25 to 0.2.26 with postgresql #7109
Comments
We have the same problem on postgres 12. Worked fine up until 0.2.25 |
Here is a workaround I found, tested with Before calling const queryRunner = selectQueryBuilder.connection.createQueryRunner("slave");
selectQueryBuilder.setQueryRunner(queryRunner);
const stream = await selectQueryBuilder.stream();
stream.on('error' => queryRunner.release());
stream.on('end' => queryRunner.release());
stream.on('data' => (rawRow) => { /* ... */ } );
... I think this worked (at least for me) because when typeorm/src/query-builder/SelectQueryBuilder.ts Lines 1264 to 1267 in c4a36da
queryRunner.release() too early - the queryRunner might not be connected yet, its connection flow finishes after the release() call and so it remains connected forever.
With pre-created |
@stvvt I didn't use queryRunner, This is my code @Injectable()
export class PositionService {
constructor(@InjectRepository(PositionEntity) private readonly positionRepository: Repository<PositionEntity>) {}
async findStreamWithEmployee(): Promise<ReadStream> {
return this.positionRepository
.createQueryBuilder('positions')
.innerJoinAndSelect('positions.employee', 'employees')
.innerJoinAndSelect('employees.card', 'cards')
.where('positions.deleted = false')
.stream();
}
} And deal with stream elsewhere. |
@IricBing This should work for you: async findStreamWithEmployee(): Promise<ReadStream> {
const queryBuilder = this.positionRepository
.createQueryBuilder('positions')
.innerJoinAndSelect('positions.employee', 'employees')
.innerJoinAndSelect('employees.card', 'cards')
.where('positions.deleted = false');
const queryRunner = queryBuilder.connection.createQueryRunner("slave");
queryBuilder.setQueryRunner(queryRunner);
const stream = queryBuilder.stream();
stream.on('error' => queryRunner.release());
stream.on('end' => queryRunner.release());
return stream;
} |
@stvvt Thanks,maybe I should upgrade my code format, although my code format is more brief. |
@stvvt Thanks! Your workaround is a bit problematic to implement in our current code. I don't mind making a PR to fix it properly, but I'm not familiar with the TypeORM codebase. Do you have any clue of what went wrong between 0.2.25 and 0.2.26? |
@alvisetrevisan I guess this change exposed the bug: ae3cf0e#diff-b924b9a6d4ab4328f4ad59d4d96b794f6a1975fae8d1d3708909e31c151730b9R106-R108 The change itself looks good. However, before it, the second (which is if fact the proper) call to |
@stvvt thanks for the pointer. I created a PR with what I think is a fix. I did not want to mess with the other drivers, so I opted for something limited to the postgres driver. |
* fix: avoid early release of PostgresQueryRunner (#7109) If the QueryRunner is not connected yet, release is a no-op * fix: avoid early release of PostgresQueryRunner (#7109) Revert no-op driver-wide early release, fix only for stream case. * fix: avoid early release of PostgresQueryRunner (#7109) Restrict stream unit test to drivers who implement the stream interface * fix: avoid early release of PostgresQueryRunner (#7109) Restrict unit test to drivers whose stream implementation works in master
@stvvt Using the latest version of typeorm (
) and postgres ( Your comment was very helpful, though. This bug occurred in a migration, and I had to go from public async up(queryRunner: QueryRunner): Promise<void> {
const stream = await queryRunner.stream(`SELECT "duration", "missionId", "landTime", "barAmount", "takeOffTime", "wingName" FROM "foos"`);
for await (const foo of stream) {
const barCount: { count: number }[] = await queryRunner.query(
`SELECT COUNT(*) FROM "bars" WHERE "fooId" = $1;`,
[foo.fooId],
);
for (let i = foo.barAmount - barCount[0].count; i > 0; --i) {
}
} to public async up(selectQueryRunner: QueryRunner): Promise<void> {
const queryRunner = selectQueryRunner.connection.createQueryRunner('slave')
const stream = await queryRunner.stream(`SELECT "duration", "missionId", "landTime", "barAmount", "takeOffTime", "wingName" FROM "foos"`, undefined, () => queryRunner.release(), () => queryRunner.release());
stream.on('error', () => queryRunner.release());
stream.on('error', () => queryRunner.release());
stream.on('data', async (foo: any) => {
const barCount: { count: number }[] = await queryRunner.query(
`SELECT COUNT(*) FROM "bars" WHERE "fooId" = $1;`,
[foo.fooId],
);
for (let i = foo.barAmount - barCount[0].count; i > 0; i--) {
}
}) And that mostly worked. |
Issue Description
I use
selectQueryBuilder.stream()
method to get a readable stream from postgresql 13. It worked very well before! Today, I create a new project and use the latest package, It block all database operation when invokeselectQueryBuilder.stream()
more than 10 times! Then I use sqlselect query from pg_stat_activity;
to get database connection, I found sql with stream not release. I'm sure it work well before, so I try to upgrade form 0.2.23 to latest version, then I found it not work from 0.2.25 to 0.2.26.Expected Behavior
selectQueryBuilder.stream()
method should release connection after stream closeActual Behavior
selectQueryBuilder.stream()
method doesn't release connectionSteps to Reproduce
0.2.26
and invokeselectQueryBuilder.stream()
method more than 10 times, or use sqlselect query from pg_stat_activity;
to get pg connections0.2.25
and try again.My Environment
Additional Context
Relevant Database Driver(s)
aurora-data-api
aurora-data-api-pg
better-sqlite3
cockroachdb
cordova
expo
mongodb
mysql
nativescript
oracle
postgres
react-native
sap
sqlite
sqlite-abstract
sqljs
sqlserver
Are you willing to resolve this issue by submitting a Pull Request?
The text was updated successfully, but these errors were encountered: