|
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'; |
@@ -1493,4 +1494,97 @@ describe('test/client.test.ts', () => { |
1493 | 1494 | assert.equal(counter2After, 4); |
1494 | 1495 | }); |
1495 | 1496 | }); |
| 1497 | + |
| 1498 | + describe('PoolWaitTimeout', () => { |
| 1499 | + async function longQuery(timeout?: number) { |
| 1500 | + await db.beginTransactionScope(async conn => { |
| 1501 | + await setTimeout(timeout ?? 1000); |
| 1502 | + await conn.query('SELECT 1+1'); |
| 1503 | + }); |
| 1504 | + } |
| 1505 | + |
| 1506 | + it('should throw error if pool wait timeout', async () => { |
| 1507 | + const tasks: Array<Promise<void>> = []; |
| 1508 | + for (let i = 0; i < 10; i++) { |
| 1509 | + tasks.push(longQuery()); |
| 1510 | + } |
| 1511 | + await assert.rejects(async () => { |
| 1512 | + await longQuery(); |
| 1513 | + }, /get connection timeout after/); |
| 1514 | + await Promise.all(tasks); |
| 1515 | + }); |
| 1516 | + |
| 1517 | + it('should release conn to pool', async () => { |
| 1518 | + const tasks: Array<Promise<void>> = []; |
| 1519 | + const timeoutTasks: Array<Promise<void>> = []; |
| 1520 | + // 1. fill the pool |
| 1521 | + for (let i = 0; i < 10; i++) { |
| 1522 | + tasks.push(longQuery()); |
| 1523 | + } |
| 1524 | + // 2. add more conn and wait for timeout |
| 1525 | + for (let i = 0; i < 10; i++) { |
| 1526 | + timeoutTasks.push(longQuery()); |
| 1527 | + } |
| 1528 | + const [ succeedTasks, failedTasks ] = await Promise.all([ |
| 1529 | + Promise.allSettled(tasks), |
| 1530 | + Promise.allSettled(timeoutTasks), |
| 1531 | + ]); |
| 1532 | + const succeedCount = succeedTasks.filter(t => t.status === 'fulfilled').length; |
| 1533 | + assert.equal(succeedCount, 10); |
| 1534 | + |
| 1535 | + const failedCount = failedTasks.filter(t => t.status === 'rejected').length; |
| 1536 | + assert.equal(failedCount, 10); |
| 1537 | + |
| 1538 | + // 3. after pool empty, create new tasks |
| 1539 | + const retryTasks: Array<Promise<void>> = []; |
| 1540 | + for (let i = 0; i < 10; i++) { |
| 1541 | + retryTasks.push(longQuery()); |
| 1542 | + } |
| 1543 | + await Promise.all(retryTasks); |
| 1544 | + }); |
| 1545 | + |
| 1546 | + it('should not wait too long', async () => { |
| 1547 | + const tasks: Array<Promise<void>> = []; |
| 1548 | + const timeoutTasks: Array<Promise<void>> = []; |
| 1549 | + const fastTasks: Array<Promise<void>> = []; |
| 1550 | + const start = performance.now(); |
| 1551 | + // 1. fill the pool |
| 1552 | + for (let i = 0; i < 10; i++) { |
| 1553 | + tasks.push(longQuery()); |
| 1554 | + } |
| 1555 | + const tasksPromise = Promise.allSettled(tasks); |
| 1556 | + // 2. add more conn and wait for timeout |
| 1557 | + for (let i = 0; i < 10; i++) { |
| 1558 | + timeoutTasks.push(longQuery()); |
| 1559 | + } |
| 1560 | + const timeoutTasksPromise = Promise.allSettled(timeoutTasks); |
| 1561 | + await setTimeout(600); |
| 1562 | + // 3. add fast query |
| 1563 | + for (let i = 0; i < 10; i++) { |
| 1564 | + fastTasks.push(longQuery(1)); |
| 1565 | + } |
| 1566 | + const fastTasksPromise = Promise.allSettled(fastTasks); |
| 1567 | + const [ succeedTasks, failedTasks, fastTaskResults ] = await Promise.all([ |
| 1568 | + tasksPromise, |
| 1569 | + timeoutTasksPromise, |
| 1570 | + fastTasksPromise, |
| 1571 | + ]); |
| 1572 | + const duration = performance.now() - start; |
| 1573 | + const succeedCount = succeedTasks.filter(t => t.status === 'fulfilled').length; |
| 1574 | + assert.equal(succeedCount, 10); |
| 1575 | + |
| 1576 | + const failedCount = failedTasks.filter(t => t.status === 'rejected').length; |
| 1577 | + assert.equal(failedCount, 10); |
| 1578 | + |
| 1579 | + const faskTaskSucceedCount = fastTaskResults.filter(t => t.status === 'fulfilled').length; |
| 1580 | + assert.equal(faskTaskSucceedCount, 10); |
| 1581 | + |
| 1582 | + // - 10 long queries cost 1000ms |
| 1583 | + // - 10 timeout queries should be timeout in long query execution so not cost time |
| 1584 | + // - 10 fast queries wait long query to finish, cost 1ms |
| 1585 | + // 1000ms + 0ms + 1ms < 1100ms |
| 1586 | + assert(duration < 1100); |
| 1587 | + }); |
| 1588 | + |
| 1589 | + }); |
1496 | 1590 | }); |
0 commit comments