Skip to content

Commit b785d9d

Browse files
authored
fix: Ensures statement requests timeout (LLC-339) (#685)
1 parent 3ac79fb commit b785d9d

File tree

13 files changed

+77
-13
lines changed

13 files changed

+77
-13
lines changed

docker-compose.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
version: '3.6'
2+
services:
3+
mongo:
4+
container_name: ll_mongo
5+
image: mongo:4.0
6+
ports:
7+
- 27017:27017
8+
volumes:
9+
- mongo-config:/data/configdb:rw
10+
- mongo-data:/data/db:rw
11+
redis:
12+
# activate persistency
13+
command: redis-server --appendonly yes
14+
container_name: ll_redis
15+
image: redis:4.0
16+
ports:
17+
- 6379:6379
18+
volumes:
19+
- redis-data:/data:rw
20+
volumes:
21+
mongo-config: {}
22+
mongo-data: {}
23+
redis-data: {}

src/apps/AppConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default interface AppConfig {
3939
};
4040
readonly mongo: {
4141
readonly db: () => Promise<Db>;
42+
readonly maxTimeMs: number;
4243
};
4344
readonly redis: {
4445
readonly prefix: string;

src/apps/statements/AppConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export default interface AppConfig {
5555
};
5656
readonly mongo: {
5757
readonly db: () => Promise<Db>;
58+
readonly maxTimeMs: number;
5859
};
5960
readonly redis: {
6061
readonly prefix: string;

src/apps/statements/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default (appConfig: AppConfig): Result => {
3030
facade: appConfig.repo.factory.modelsRepoName,
3131
mongo: {
3232
db: appConfig.repo.mongo.db,
33+
maxTimeMs: appConfig.repo.mongo.maxTimeMs,
3334
},
3435
},
3536
storage: {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import BaseError from 'jscommons/dist/errors/BaseError';
2+
3+
// tslint:disable-next-line:no-class
4+
export default class extends BaseError {
5+
// istanbul ignore next - Couldn't test without an unacceptable test duration.
6+
constructor(public readonly timeoutMs: number) {
7+
super();
8+
}
9+
}

src/apps/statements/expressPresenter/utils/handleError.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import MissingLoadedId from '../../errors/MissingLoadedId';
2727
import MissingStatementId from '../../errors/MissingStatementId';
2828
import NoStatements from '../../errors/NoStatements';
2929
import QueryIds from '../../errors/QueryIds';
30+
import Timeout from '../../errors/Timeout';
3031
import UnequalStatementId from '../../errors/UnequalStatementId';
3132
import UnknownParams from '../../errors/UnknownParams';
3233
import UntrustedClientError from '../../errors/UntrustedClientError';
@@ -210,6 +211,11 @@ export default ({ config, errorId, res, err }: Options): Response => {
210211
const message = translator.untrustedClientError(err);
211212
return sendMessage({ res, code, errorId, message });
212213
}
214+
if (err instanceof Timeout) {
215+
const code = BAD_REQUEST;
216+
const message = translator.timeoutError(err);
217+
return sendMessage({ res, code, errorId, message });
218+
}
213219
return commonErrorHandler({ config, errorId, res, err });
214220
// tslint:disable-next-line:max-file-line-count
215221
};

src/apps/statements/repo/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const repo: Repo = factory({
3131
facade: config.repoFactory.modelsRepoName,
3232
mongo: {
3333
db: connectToMongoDb(),
34+
maxTimeMs: config.defaultTimeout,
3435
},
3536
},
3637
storage: {

src/apps/statements/repo/modelsRepo/getStatements/mongo/index.ts

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { defaultTo } from 'lodash';
2+
import Timeout from '../../../../errors/Timeout';
23
import StoredStatementModel from '../../../../models/StoredStatementModel';
34
import { STATEMENTS_COLLECTION_NAME } from '../../utils/mongoModels/constants';
45
import FacadeConfig from '../../utils/mongoModels/FacadeConfig';
@@ -44,18 +45,28 @@ export default (config: FacadeConfig): Signature => {
4445
const skip = defaultTo(opts.skip, 0);
4546
const limit = opts.limit;
4647

47-
const models = await collection
48-
.find(query)
49-
.sort(sort)
50-
.skip(skip)
51-
.limit(limit)
52-
.toArray() as StoredStatementModel[];
48+
try {
49+
const models = await collection
50+
.find(query)
51+
.sort(sort)
52+
.skip(skip)
53+
.limit(limit)
54+
.maxTimeMS(config.maxTimeMs)
55+
.toArray() as StoredStatementModel[];
5356

54-
const decodedModels = models.map((model) => {
55-
const statement = decodeDotsInStatement(model.statement);
56-
return { ...model, statement };
57-
});
57+
const decodedModels = models.map((model) => {
58+
const statement = decodeDotsInStatement(model.statement);
59+
return { ...model, statement };
60+
});
5861

59-
return decodedModels;
62+
return decodedModels;
63+
} catch (err) {
64+
// istanbul ignore next - Couldn't test without an unacceptable test duration.
65+
if (err?.code === 50) {
66+
throw new Timeout(config.maxTimeMs);
67+
}
68+
// istanbul ignore next - Unexpected error.
69+
throw err;
70+
}
6071
};
6172
};

src/apps/statements/repo/modelsRepo/utils/mongoModels/FacadeConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Db } from 'mongodb';
22

33
interface Config {
44
readonly db: () => Promise<Db>;
5+
readonly maxTimeMs: number;
56
}
67

78
export default Config;

src/apps/statements/repo/modelsRepo/utils/mongoModels/factory.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ import voidStatements from '../../voidStatements/mongo';
1818
import FacadeConfig from './FacadeConfig';
1919
import FactoryConfig from './FactoryConfig';
2020

21+
const defaultMaxTimeMs = 300000; // 5 minutes.
22+
2123
export default (factoryConfig?: FactoryConfig): Facade => {
2224
const facadeConfig: FacadeConfig = (
2325
factoryConfig !== undefined
2426
? factoryConfig
25-
: { db: connectToMongoDb() }
27+
: { db: connectToMongoDb(), maxTimeMs: defaultMaxTimeMs }
2628
);
2729
return {
2830
clearRepo: async () => {

0 commit comments

Comments
 (0)