Skip to content

Commit f6f83fc

Browse files
committed
Add concurrent request limit
1 parent f6c68ec commit f6f83fc

File tree

3 files changed

+36
-3
lines changed

3 files changed

+36
-3
lines changed

src/config.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ addDefaults(config, {
7676
port: 5432,
7777
max: 10,
7878
idleTimeoutMillis: 10000,
79-
maxTries: 3
79+
maxTries: 3,
80+
maxConcurrentRequests: 3500
8081
},
8182
postgresReadOnly: {
8283
enabled: false,
@@ -89,7 +90,8 @@ addDefaults(config, {
8990
max: 10,
9091
idleTimeoutMillis: 10000,
9192
maxTries: 3,
92-
fallbackOnFail: true
93+
fallbackOnFail: true,
94+
maxConcurrentRequests: 3500
9395
},
9496
dumpDatabase: {
9597
enabled: false,

src/databases/Postgres.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export class Postgres implements IDatabase {
3333
private poolRead: Pool;
3434
private lastPoolReadFail = 0;
3535

36+
private concurrentRequests = 0;
37+
private concurrentReadRequests = 0;
38+
3639
constructor(private config: DatabaseConfig) {}
3740

3841
async init(): Promise<void> {
@@ -99,8 +102,23 @@ export class Postgres implements IDatabase {
99102

100103
Logger.debug(`prepare (postgres): type: ${type}, query: ${query}, params: ${params}`);
101104

102-
const pendingQueries: PromiseWithState<QueryResult<any>>[] = [];
105+
if (this.config.readOnly) {
106+
if (this.concurrentReadRequests > this.config.postgresReadOnly?.maxConcurrentRequests) {
107+
Logger.error(`prepare (postgres): cancelling read query because too many concurrent requests, query: ${query}`);
108+
throw new Error("Too many concurrent requests");
109+
}
110+
111+
this.concurrentReadRequests++;
112+
} else {
113+
if (this.concurrentRequests > this.config.postgres.maxConcurrentRequests) {
114+
Logger.error(`prepare (postgres): cancelling query because too many concurrent requests, query: ${query}`);
115+
throw new Error("Too many concurrent requests");
116+
}
117+
118+
this.concurrentRequests++;
119+
}
103120

121+
const pendingQueries: PromiseWithState<QueryResult<any>>[] = [];
104122
let tries = 0;
105123
let lastPool: Pool = null;
106124
const maxTries = () => (lastPool === this.pool
@@ -116,6 +134,12 @@ export class Postgres implements IDatabase {
116134
if (options.useReplica && maxTries() - tries > 1) currentPromises.push(savePromiseState(timeoutPomise(this.config.postgresReadOnly.readTimeout)));
117135
const queryResult = await nextFulfilment(currentPromises);
118136

137+
if (this.config.readOnly) {
138+
this.concurrentReadRequests--;
139+
} else {
140+
this.concurrentRequests--;
141+
}
142+
119143
switch (type) {
120144
case "get": {
121145
const value = queryResult.rows[0];
@@ -143,6 +167,12 @@ export class Postgres implements IDatabase {
143167
}
144168
} while (this.isReadQuery(type) && tries < maxTries());
145169

170+
if (this.config.readOnly) {
171+
this.concurrentReadRequests--;
172+
} else {
173+
this.concurrentRequests--;
174+
}
175+
146176
throw new Error(`prepare (postgres): ${type} ${query} failed after ${tries} tries`);
147177
}
148178

src/types/config.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface RedisConfig extends redis.RedisClientOptions {
1010
export interface CustomPostgresConfig extends PoolConfig {
1111
enabled: boolean;
1212
maxTries: number;
13+
maxConcurrentRequests: number;
1314
}
1415

1516
export interface CustomPostgresReadOnlyConfig extends CustomPostgresConfig {

0 commit comments

Comments
 (0)