Skip to content

Commit 393bad4

Browse files
authored
feat(Statement): Add alternative publish to queue logic without using Redis (LLC-2162) (#890)
1 parent 22ea51f commit 393bad4

File tree

17 files changed

+583
-0
lines changed

17 files changed

+583
-0
lines changed

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ EXPRESS_PORT=8081
9595
###############################
9696
# Uncomment next line if you want to enable statement handling priority
9797
#ENABLE_QUEUE_PRIORITY=true
98+
# Event provider(redis|sqs). Redis by default
99+
#EVENTS_REPO=redis
100+
# Queue namespace
101+
#QUEUE_NAMESPACE=DEV
98102

99103
##########
100104
# Misc #

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
},
4141
"dependencies": {
4242
"@aws-sdk/client-s3": "^3.100.0",
43+
"@aws-sdk/client-sqs": "^3.282.0",
4344
"@aws-sdk/lib-storage": "^3.100.0",
4445
"@azure/storage-blob": "^10.3.0",
4546
"@google-cloud/storage": "^5.8.1",
@@ -208,6 +209,8 @@
208209
"functional/prefer-type-literal": "off",
209210
"functional/no-throw-statement": "off",
210211
"functional/no-try-statement": "off",
212+
"functional/no-let": "off",
213+
"functional/no-loop-statement": "off",
211214
"functional/prefer-readonly-type": [
212215
"error",
213216
{

src/apps/AppConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Redis } from 'ioredis';
33
import Tracker from 'jscommons/dist/tracker/Tracker';
44
import { Db } from 'mongodb';
55
import { LoggerInstance } from 'winston';
6+
import { SQSClient } from '@aws-sdk/client-sqs';
67

78
export default interface AppConfig {
89
readonly repo: {
@@ -46,6 +47,11 @@ export default interface AppConfig {
4647
readonly client: () => Promise<Redis>;
4748
readonly isQueuePriorityEnabled: boolean;
4849
};
50+
readonly sqs: {
51+
readonly prefix: string;
52+
readonly client: () => Promise<SQSClient>;
53+
readonly isQueuePriorityEnabled: boolean;
54+
};
4955
};
5056
readonly service: {
5157
readonly statements: {

src/apps/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export default (appConfig: AppConfig): Router => {
8181
local: appConfig.repo.local,
8282
mongo: appConfig.repo.mongo,
8383
redis: appConfig.repo.redis,
84+
sqs: appConfig.repo.sqs,
8485
s3: appConfig.repo.s3,
8586
storageSubFolder: appConfig.repo.storageSubFolders.statements,
8687
},

src/apps/statements/AppConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Redis } from 'ioredis';
33
import Tracker from 'jscommons/dist/tracker/Tracker';
44
import { Db } from 'mongodb';
55
import { LoggerInstance } from 'winston';
6+
import { SQSClient } from '@aws-sdk/client-sqs';
67

78
export default interface AppConfig {
89
readonly logger: LoggerInstance;
@@ -62,5 +63,10 @@ export default interface AppConfig {
6263
readonly client: () => Promise<Redis>;
6364
readonly isQueuePriorityEnabled: boolean;
6465
};
66+
readonly sqs: {
67+
readonly prefix: string;
68+
readonly client: () => Promise<SQSClient>;
69+
readonly isQueuePriorityEnabled: boolean;
70+
};
6571
};
6672
}

src/apps/statements/app.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export default (appConfig: AppConfig): Result => {
2121
prefix: appConfig.repo.redis.prefix,
2222
isQueuePriorityEnabled: appConfig.repo.redis.isQueuePriorityEnabled,
2323
},
24+
sqs: {
25+
client: appConfig.repo.sqs.client,
26+
prefix: appConfig.repo.sqs.prefix,
27+
isQueuePriorityEnabled: appConfig.repo.sqs.isQueuePriorityEnabled,
28+
},
2429
},
2530
models: {
2631
facade: appConfig.repo.factory.modelsRepoName,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import RedisFactoryConfig from './utils/redisEvents/FactoryConfig';
2+
import SQSFactoryConfig from './utils/sqsEvents/FactoryConfig';
23

34
export default interface FactoryConfig {
45
readonly facade?: string;
56
readonly redis?: RedisFactoryConfig;
7+
readonly sqs?: SQSFactoryConfig;
68
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import {
2+
GetQueueUrlCommand,
3+
SQSClient,
4+
SendMessageBatchCommand,
5+
SendMessageBatchRequestEntry,
6+
} from '@aws-sdk/client-sqs';
7+
import { v4 } from 'uuid';
8+
import { getPrefixWithProcessingPriority } from '../utils/getPrefixWithProcessingPriority';
9+
import { StatementProcessingPriority } from '../../../enums/statementProcessingPriority.enum';
10+
import FacadeConfig from '../utils/sqsEvents/FacadeConfig';
11+
import { STATEMENT_QUEUE } from '../utils/constants';
12+
import Signature from './Signature';
13+
14+
const MAX_BATCH_SIZE = 10;
15+
16+
let queueUrl: string | undefined;
17+
18+
const publishMessages = async (sqsClient: SQSClient, statementProperties: string[]) => {
19+
const statementPropertiesBatchRequest = statementProperties.map(
20+
(statementProperty): SendMessageBatchRequestEntry => ({
21+
Id: v4(),
22+
MessageBody: statementProperty,
23+
}),
24+
);
25+
26+
for (let index = 0; index < statementPropertiesBatchRequest.length; index += MAX_BATCH_SIZE) {
27+
await sqsClient.send(
28+
new SendMessageBatchCommand({
29+
QueueUrl: queueUrl,
30+
Entries: statementPropertiesBatchRequest.slice(index, index + MAX_BATCH_SIZE),
31+
}),
32+
);
33+
}
34+
};
35+
36+
const getQueueUrl = async (
37+
sqsClient: SQSClient,
38+
prefix: string,
39+
priority: StatementProcessingPriority,
40+
isQueuePriorityEnabled: boolean,
41+
) => {
42+
if (queueUrl) {
43+
return queueUrl;
44+
}
45+
46+
const prefixWithPriority = getPrefixWithProcessingPriority(
47+
prefix,
48+
priority,
49+
isQueuePriorityEnabled,
50+
);
51+
52+
const getQueueUrlCommand = new GetQueueUrlCommand({
53+
QueueName: `${prefixWithPriority}_${STATEMENT_QUEUE}`,
54+
});
55+
56+
const commandResult = await sqsClient.send(getQueueUrlCommand);
57+
58+
queueUrl = commandResult.QueueUrl;
59+
60+
return queueUrl;
61+
};
62+
63+
export default (config: FacadeConfig): Signature => {
64+
return async ({ statementProperties, priority }) => {
65+
const sqsClient = await config.client();
66+
67+
await getQueueUrl(sqsClient, config.prefix, priority, config.isQueuePriorityEnabled);
68+
await publishMessages(sqsClient, statementProperties);
69+
};
70+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import Facade from './Facade';
22
import FactoryConfig from './FactoryConfig';
33
import redisFactory from './utils/redisEvents/factory';
4+
import sqsFactory from './utils/sqsEvents/factory';
45

56
export default (config: FactoryConfig): Facade => {
67
switch (config.facade) {
78
default:
89
case 'redis':
910
return redisFactory(config.redis);
11+
case 'sqs':
12+
return sqsFactory(config.sqs);
1013
}
1114
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export const EVENT_NAME = 'statement.new';
22
export const CHANNEL_NAME = 'statement.notify';
3+
export const STATEMENT_QUEUE = 'STATEMENT_QUEUE';

0 commit comments

Comments
 (0)