|
1 | 1 | import { AsyncLocalStorage } from 'node:async_hooks';
|
2 | 2 | import { strict as assert } from 'node:assert';
|
3 | 3 | import fs from 'node:fs/promises';
|
| 4 | +import { setTimeout } from 'node:timers/promises'; |
4 | 5 | import path from 'node:path';
|
5 | 6 | import mm from 'mm';
|
6 | 7 | import { RDSTransaction } from '../src/transaction';
|
@@ -298,8 +299,9 @@ describe('test/client.test.ts', () => {
|
298 | 299 | // recovered after unlock.
|
299 | 300 | await conn.query('select * from `myrds-test-user` limit 1;');
|
300 | 301 | } catch (err) {
|
301 |
| - conn.release(); |
302 | 302 | throw err;
|
| 303 | + } finally { |
| 304 | + conn.release(); |
303 | 305 | }
|
304 | 306 | });
|
305 | 307 |
|
@@ -353,7 +355,8 @@ describe('test/client.test.ts', () => {
|
353 | 355 | });
|
354 | 356 |
|
355 | 357 | it('should throw rollback error with cause error when rollback failed', async () => {
|
356 |
| - mm(RDSTransaction.prototype, 'rollback', async () => { |
| 358 | + mm(RDSTransaction.prototype, 'rollback', async function(this: RDSTransaction) { |
| 359 | + this.conn!.release(); |
357 | 360 | throw new Error('fake rollback error');
|
358 | 361 | });
|
359 | 362 | await assert.rejects(
|
@@ -501,7 +504,9 @@ describe('test/client.test.ts', () => {
|
501 | 504 | });
|
502 | 505 | };
|
503 | 506 |
|
504 |
| - const [ p1Res, p2Res ] = await Promise.all([ p1(), p2().catch(err => err) ]); |
| 507 | + const [ p1Res, p2Res ] = await Promise.all([ p1(), p2().catch(err => { |
| 508 | + return err; |
| 509 | + }) ]); |
505 | 510 | assert.strictEqual(p1Res, true);
|
506 | 511 | assert.strictEqual(p2Res.code, 'ER_PARSE_ERROR');
|
507 | 512 | const rows = await db.query('select * from ?? where email=? order by id',
|
@@ -680,6 +685,7 @@ describe('test/client.test.ts', () => {
|
680 | 685 | });
|
681 | 686 | return db;
|
682 | 687 | });
|
| 688 | + conn.release(); |
683 | 689 | assert(connQuerySql);
|
684 | 690 | assert(!transactionQuerySql);
|
685 | 691 | });
|
@@ -1493,4 +1499,98 @@ describe('test/client.test.ts', () => {
|
1493 | 1499 | assert.equal(counter2After, 4);
|
1494 | 1500 | });
|
1495 | 1501 | });
|
| 1502 | + |
| 1503 | + describe('PoolWaitTimeout', () => { |
| 1504 | + async function longQuery(timeout?: number) { |
| 1505 | + await db.beginTransactionScope(async conn => { |
| 1506 | + await setTimeout(timeout ?? 1000); |
| 1507 | + await conn.query('SELECT 1+1'); |
| 1508 | + }); |
| 1509 | + } |
| 1510 | + |
| 1511 | + it('should throw error if pool wait timeout', async () => { |
| 1512 | + const tasks: Array<Promise<void>> = []; |
| 1513 | + for (let i = 0; i < 10; i++) { |
| 1514 | + tasks.push(longQuery()); |
| 1515 | + } |
| 1516 | + const tasksPromise = Promise.all(tasks); |
| 1517 | + await assert.rejects(async () => { |
| 1518 | + await longQuery(); |
| 1519 | + }, /get connection timeout after/); |
| 1520 | + await tasksPromise; |
| 1521 | + }); |
| 1522 | + |
| 1523 | + it('should release conn to pool', async () => { |
| 1524 | + const tasks: Array<Promise<void>> = []; |
| 1525 | + const timeoutTasks: Array<Promise<void>> = []; |
| 1526 | + // 1. fill the pool |
| 1527 | + for (let i = 0; i < 10; i++) { |
| 1528 | + tasks.push(longQuery()); |
| 1529 | + } |
| 1530 | + // 2. add more conn and wait for timeout |
| 1531 | + for (let i = 0; i < 10; i++) { |
| 1532 | + timeoutTasks.push(longQuery()); |
| 1533 | + } |
| 1534 | + const [ succeedTasks, failedTasks ] = await Promise.all([ |
| 1535 | + Promise.allSettled(tasks), |
| 1536 | + Promise.allSettled(timeoutTasks), |
| 1537 | + ]); |
| 1538 | + const succeedCount = succeedTasks.filter(t => t.status === 'fulfilled').length; |
| 1539 | + assert.equal(succeedCount, 10); |
| 1540 | + |
| 1541 | + const failedCount = failedTasks.filter(t => t.status === 'rejected').length; |
| 1542 | + assert.equal(failedCount, 10); |
| 1543 | + |
| 1544 | + // 3. after pool empty, create new tasks |
| 1545 | + const retryTasks: Array<Promise<void>> = []; |
| 1546 | + for (let i = 0; i < 10; i++) { |
| 1547 | + retryTasks.push(longQuery()); |
| 1548 | + } |
| 1549 | + await Promise.all(retryTasks); |
| 1550 | + }); |
| 1551 | + |
| 1552 | + it('should not wait too long', async () => { |
| 1553 | + const tasks: Array<Promise<void>> = []; |
| 1554 | + const timeoutTasks: Array<Promise<void>> = []; |
| 1555 | + const fastTasks: Array<Promise<void>> = []; |
| 1556 | + const start = performance.now(); |
| 1557 | + // 1. fill the pool |
| 1558 | + for (let i = 0; i < 10; i++) { |
| 1559 | + tasks.push(longQuery()); |
| 1560 | + } |
| 1561 | + const tasksPromise = Promise.allSettled(tasks); |
| 1562 | + // 2. add more conn and wait for timeout |
| 1563 | + for (let i = 0; i < 10; i++) { |
| 1564 | + timeoutTasks.push(longQuery()); |
| 1565 | + } |
| 1566 | + const timeoutTasksPromise = Promise.allSettled(timeoutTasks); |
| 1567 | + await setTimeout(600); |
| 1568 | + // 3. add fast query |
| 1569 | + for (let i = 0; i < 10; i++) { |
| 1570 | + fastTasks.push(longQuery(1)); |
| 1571 | + } |
| 1572 | + const fastTasksPromise = Promise.allSettled(fastTasks); |
| 1573 | + const [ succeedTasks, failedTasks, fastTaskResults ] = await Promise.all([ |
| 1574 | + tasksPromise, |
| 1575 | + timeoutTasksPromise, |
| 1576 | + fastTasksPromise, |
| 1577 | + ]); |
| 1578 | + const duration = performance.now() - start; |
| 1579 | + const succeedCount = succeedTasks.filter(t => t.status === 'fulfilled').length; |
| 1580 | + assert.equal(succeedCount, 10); |
| 1581 | + |
| 1582 | + const failedCount = failedTasks.filter(t => t.status === 'rejected').length; |
| 1583 | + assert.equal(failedCount, 10); |
| 1584 | + |
| 1585 | + const faskTaskSucceedCount = fastTaskResults.filter(t => t.status === 'fulfilled').length; |
| 1586 | + assert.equal(faskTaskSucceedCount, 10); |
| 1587 | + |
| 1588 | + // - 10 long queries cost 1000ms |
| 1589 | + // - 10 timeout queries should be timeout in long query execution so not cost time |
| 1590 | + // - 10 fast queries wait long query to finish, cost 1ms |
| 1591 | + // 1000ms + 0ms + 1ms < 1100ms |
| 1592 | + assert(duration < 1100); |
| 1593 | + }); |
| 1594 | + |
| 1595 | + }); |
1496 | 1596 | });
|
0 commit comments