@squiz/optimization-utils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloudflare/CloudflareKVHttpService.d.ts +11 -0
- package/dist/cloudflare/CloudflareKVHttpService.js +19 -0
- package/dist/cloudflare/CloudflareKVHttpService.js.map +1 -0
- package/dist/cloudflare/ImplCloudflareKVHttpService.d.ts +22 -0
- package/dist/cloudflare/ImplCloudflareKVHttpService.js +96 -0
- package/dist/cloudflare/ImplCloudflareKVHttpService.js.map +1 -0
- package/dist/config/ConfigurationLoader.d.ts +23 -0
- package/dist/config/ConfigurationLoader.js +99 -0
- package/dist/config/ConfigurationLoader.js.map +1 -0
- package/dist/date/DateManipulator.d.ts +6 -0
- package/dist/date/DateManipulator.js +21 -0
- package/dist/date/DateManipulator.js.map +1 -0
- package/dist/event/AggregateRoot.d.ts +4 -0
- package/dist/event/AggregateRoot.js +3 -0
- package/dist/event/AggregateRoot.js.map +1 -0
- package/dist/event/DomainEvent.d.ts +13 -0
- package/dist/event/DomainEvent.js +28 -0
- package/dist/event/DomainEvent.js.map +1 -0
- package/dist/event/DynamoDBEventMapper.d.ts +36 -0
- package/dist/event/DynamoDBEventMapper.js +55 -0
- package/dist/event/DynamoDBEventMapper.js.map +1 -0
- package/dist/event/EventHandler.d.ts +14 -0
- package/dist/event/EventHandler.js +43 -0
- package/dist/event/EventHandler.js.map +1 -0
- package/dist/exception/DomainException.d.ts +18 -0
- package/dist/exception/DomainException.js +41 -0
- package/dist/exception/DomainException.js.map +1 -0
- package/dist/httpClient/FetchHttpClient.d.ts +7 -0
- package/dist/httpClient/FetchHttpClient.js +86 -0
- package/dist/httpClient/FetchHttpClient.js.map +1 -0
- package/dist/httpClient/HttpClient.d.ts +25 -0
- package/dist/httpClient/HttpClient.js +45 -0
- package/dist/httpClient/HttpClient.js.map +1 -0
- package/dist/httpClient/HttpRequestBuilder.d.ts +22 -0
- package/dist/httpClient/HttpRequestBuilder.js +126 -0
- package/dist/httpClient/HttpRequestBuilder.js.map +1 -0
- package/dist/logger/Logger.d.ts +10 -0
- package/dist/logger/Logger.js +30 -0
- package/dist/logger/Logger.js.map +1 -0
- package/dist/logger/LoggerMessage.d.ts +27 -0
- package/dist/logger/LoggerMessage.js +94 -0
- package/dist/logger/LoggerMessage.js.map +1 -0
- package/dist/logger/RemoteLogger.d.ts +30 -0
- package/dist/logger/RemoteLogger.js +35 -0
- package/dist/logger/RemoteLogger.js.map +1 -0
- package/dist/logger/SquizRemoteLogger.d.ts +53 -0
- package/dist/logger/SquizRemoteLogger.js +128 -0
- package/dist/logger/SquizRemoteLogger.js.map +1 -0
- package/dist/package.d.ts +23 -0
- package/dist/package.js +40 -0
- package/dist/package.js.map +1 -0
- package/dist/scheduler/EventBridgeScheduler.d.ts +21 -0
- package/dist/scheduler/EventBridgeScheduler.js +131 -0
- package/dist/scheduler/EventBridgeScheduler.js.map +1 -0
- package/dist/scheduler/Scheduler.d.ts +21 -0
- package/dist/scheduler/Scheduler.js +17 -0
- package/dist/scheduler/Scheduler.js.map +1 -0
- package/dist/testing/mock.d.ts +12 -0
- package/dist/testing/mock.js +51 -0
- package/dist/testing/mock.js.map +1 -0
- package/dist/typesUtils/DynamoDB.d.ts +4 -0
- package/dist/typesUtils/DynamoDB.js +3 -0
- package/dist/typesUtils/DynamoDB.js.map +1 -0
- package/dist/typesUtils/utilities.d.ts +9 -0
- package/dist/typesUtils/utilities.js +3 -0
- package/dist/typesUtils/utilities.js.map +1 -0
- package/dist/validation/handleValidation.d.ts +2 -0
- package/dist/validation/handleValidation.js +11 -0
- package/dist/validation/handleValidation.js.map +1 -0
- package/dist/valueObject/TenantId.d.ts +10 -0
- package/dist/valueObject/TenantId.js +23 -0
- package/dist/valueObject/TenantId.js.map +1 -0
- package/package.json +26 -0
- package/src/cloudflare/CloudflareKVHttpService.ts +20 -0
- package/src/cloudflare/ImplCloudflareKVHttpService.ts +128 -0
- package/src/cloudflare/__tests__/ImplCloudflareKVHttpService.spec.ts +178 -0
- package/src/config/ConfigurationLoader.ts +72 -0
- package/src/config/__tests__/ConfigurationLoader.spec.ts +62 -0
- package/src/date/DateManipulator.ts +29 -0
- package/src/date/__tests__/DateManipulator.spec.ts +64 -0
- package/src/event/AggregateRoot.ts +5 -0
- package/src/event/DomainEvent.ts +52 -0
- package/src/event/DynamoDBEventMapper.ts +72 -0
- package/src/event/EventHandler.ts +57 -0
- package/src/event/__tests__/DynamoDBEventMapper.spec.ts +113 -0
- package/src/exception/DomainException.ts +34 -0
- package/src/httpClient/FetchHttpClient.ts +92 -0
- package/src/httpClient/HttpClient.ts +46 -0
- package/src/httpClient/HttpRequestBuilder.ts +120 -0
- package/src/httpClient/__tests__/FetchHttpClient.spec.ts +146 -0
- package/src/httpClient/__tests__/HttpClient.spec.ts +52 -0
- package/src/httpClient/__tests__/httpRequestBuilder.spec.ts +75 -0
- package/src/logger/Logger.ts +40 -0
- package/src/logger/LoggerMessage.ts +151 -0
- package/src/logger/RemoteLogger.ts +32 -0
- package/src/logger/SquizRemoteLogger.ts +157 -0
- package/src/logger/__tests__/LoggerMessage.spec.ts +133 -0
- package/src/logger/__tests__/SquizRemoteLogger.spec.ts +185 -0
- package/src/package.ts +23 -0
- package/src/scheduler/EventBridgeScheduler.ts +177 -0
- package/src/scheduler/Scheduler.ts +32 -0
- package/src/scheduler/__tests__/EventBridgeScheduler.spec.ts +310 -0
- package/src/testing/mock.ts +62 -0
- package/src/typesUtils/DynamoDB.ts +17 -0
- package/src/typesUtils/utilities.ts +11 -0
- package/src/validation/handleValidation.ts +13 -0
- package/src/valueObject/TenantId.ts +27 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { createHttpClientMock, createLoggerMock } from '../../testing/mock';
|
|
3
|
+
import { Container } from 'inversify';
|
|
4
|
+
import { HttpRequestBuilderFactory } from '../../httpClient/HttpRequestBuilder';
|
|
5
|
+
import {
|
|
6
|
+
HttpClient,
|
|
7
|
+
HttpMethod,
|
|
8
|
+
HttpRequestOptions,
|
|
9
|
+
HttpResponse,
|
|
10
|
+
} from '../../httpClient/HttpClient';
|
|
11
|
+
import { Logger } from '../Logger';
|
|
12
|
+
import {
|
|
13
|
+
CreateLogsRequestBodyDto,
|
|
14
|
+
SquizRemoteLogger,
|
|
15
|
+
SquizRemoteLoggerServiceConfigProvider,
|
|
16
|
+
} from '../SquizRemoteLogger';
|
|
17
|
+
import { RemoteLogLevel, RemoteLogger } from '../RemoteLogger';
|
|
18
|
+
import { TenantId } from '../../valueObject/TenantId';
|
|
19
|
+
|
|
20
|
+
describe('SquizRemoteLogger', () => {
|
|
21
|
+
let logger: RemoteLogger;
|
|
22
|
+
let httpClient: HttpClient;
|
|
23
|
+
const config: Awaited<ReturnType<SquizRemoteLoggerServiceConfigProvider>> = {
|
|
24
|
+
loggerServiceUrl: new URL(
|
|
25
|
+
'https://develop-apps-dxp-console.dev.dxp.squiz.cloud',
|
|
26
|
+
),
|
|
27
|
+
createLogsPath: '/__dxp/us/logging',
|
|
28
|
+
apiKey: 'apiKey',
|
|
29
|
+
serviceName: 'experiment',
|
|
30
|
+
};
|
|
31
|
+
const expectedPayload = (
|
|
32
|
+
tenantId: string,
|
|
33
|
+
body: CreateLogsRequestBodyDto,
|
|
34
|
+
): HttpRequestOptions => {
|
|
35
|
+
return {
|
|
36
|
+
url: new URL(
|
|
37
|
+
`https://develop-apps-dxp-console.dev.dxp.squiz.cloud/__dxp/us/logging/${tenantId}`,
|
|
38
|
+
),
|
|
39
|
+
method: HttpMethod.POST,
|
|
40
|
+
body,
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
'x-api-key': 'apiKey',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
const container = new Container({ defaultScope: 'Singleton' });
|
|
50
|
+
|
|
51
|
+
container.bind(SquizRemoteLogger).toDynamicValue(({ container: c }) => {
|
|
52
|
+
return new SquizRemoteLogger(
|
|
53
|
+
() => Promise.resolve(config),
|
|
54
|
+
c.get(Logger),
|
|
55
|
+
c.get(HttpRequestBuilderFactory),
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
container.bind(Logger).toConstantValue(createLoggerMock());
|
|
59
|
+
container.bind(HttpRequestBuilderFactory).toSelf();
|
|
60
|
+
container.bind(HttpClient).toConstantValue(createHttpClientMock());
|
|
61
|
+
|
|
62
|
+
httpClient = container.get(HttpClient);
|
|
63
|
+
logger = container.get(SquizRemoteLogger);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('batch logging', () => {
|
|
67
|
+
it('should send logs for particular tenant in one call', async () => {
|
|
68
|
+
jest
|
|
69
|
+
.spyOn(httpClient, 'sendRequest')
|
|
70
|
+
.mockResolvedValueOnce(new HttpResponse({ statusCode: 201, body: {} }))
|
|
71
|
+
.mockResolvedValueOnce(new HttpResponse({ statusCode: 201, body: {} }));
|
|
72
|
+
const logs = [
|
|
73
|
+
{
|
|
74
|
+
level: RemoteLogLevel.INFO,
|
|
75
|
+
message: faker.word.words(),
|
|
76
|
+
timestamp: faker.date.past(),
|
|
77
|
+
tenantId: new TenantId('1'),
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
level: RemoteLogLevel.INFO,
|
|
81
|
+
message: faker.word.words(),
|
|
82
|
+
timestamp: faker.date.past(),
|
|
83
|
+
tenantId: new TenantId('1'),
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
level: RemoteLogLevel.INFO,
|
|
87
|
+
message: faker.word.words(),
|
|
88
|
+
timestamp: faker.date.past(),
|
|
89
|
+
tenantId: new TenantId('2'),
|
|
90
|
+
},
|
|
91
|
+
] as const;
|
|
92
|
+
|
|
93
|
+
await logger.log(logs);
|
|
94
|
+
|
|
95
|
+
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
96
|
+
expectedPayload('1', [
|
|
97
|
+
{
|
|
98
|
+
level: 'INFO',
|
|
99
|
+
message: logs[0].message,
|
|
100
|
+
timestamp: logs[0].timestamp.toISOString(),
|
|
101
|
+
service: 'experiment',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
level: 'INFO',
|
|
105
|
+
message: logs[1].message,
|
|
106
|
+
timestamp: logs[1].timestamp.toISOString(),
|
|
107
|
+
service: 'experiment',
|
|
108
|
+
},
|
|
109
|
+
]),
|
|
110
|
+
);
|
|
111
|
+
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
112
|
+
expectedPayload('2', [
|
|
113
|
+
{
|
|
114
|
+
level: 'INFO',
|
|
115
|
+
message: logs[2].message,
|
|
116
|
+
timestamp: logs[2].timestamp.toISOString(),
|
|
117
|
+
service: 'experiment',
|
|
118
|
+
},
|
|
119
|
+
]),
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('simple logging', () => {
|
|
125
|
+
const log = {
|
|
126
|
+
message: faker.word.words(),
|
|
127
|
+
timestamp: faker.date.past(),
|
|
128
|
+
tenantId: new TenantId('1'),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
beforeEach(() => {
|
|
132
|
+
jest.spyOn(httpClient, 'sendRequest').mockResolvedValueOnce(
|
|
133
|
+
new HttpResponse({
|
|
134
|
+
statusCode: 201,
|
|
135
|
+
body: {},
|
|
136
|
+
}),
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should send INFO log', async () => {
|
|
141
|
+
await logger.info(log);
|
|
142
|
+
|
|
143
|
+
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
144
|
+
expectedPayload(log.tenantId.valueOf(), [
|
|
145
|
+
{
|
|
146
|
+
message: log.message,
|
|
147
|
+
timestamp: log.timestamp.toISOString(),
|
|
148
|
+
level: 'INFO',
|
|
149
|
+
service: 'experiment',
|
|
150
|
+
},
|
|
151
|
+
]),
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should send WARN log', async () => {
|
|
156
|
+
await logger.warn(log);
|
|
157
|
+
|
|
158
|
+
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
159
|
+
expectedPayload(log.tenantId.valueOf(), [
|
|
160
|
+
{
|
|
161
|
+
message: log.message,
|
|
162
|
+
timestamp: log.timestamp.toISOString(),
|
|
163
|
+
level: 'WARNING',
|
|
164
|
+
service: 'experiment',
|
|
165
|
+
},
|
|
166
|
+
]),
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should send ERROR log', async () => {
|
|
171
|
+
await logger.error(log);
|
|
172
|
+
|
|
173
|
+
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
174
|
+
expectedPayload(log.tenantId.valueOf(), [
|
|
175
|
+
{
|
|
176
|
+
message: log.message,
|
|
177
|
+
timestamp: log.timestamp.toISOString(),
|
|
178
|
+
level: 'ERROR',
|
|
179
|
+
service: 'experiment',
|
|
180
|
+
},
|
|
181
|
+
]),
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
package/src/package.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export * from './valueObject/TenantId';
|
|
2
|
+
export * from './validation/handleValidation';
|
|
3
|
+
export * from './typesUtils/utilities';
|
|
4
|
+
export * from './typesUtils/DynamoDB';
|
|
5
|
+
export * from './testing/mock';
|
|
6
|
+
export * from './scheduler/Scheduler';
|
|
7
|
+
export * from './scheduler/EventBridgeScheduler';
|
|
8
|
+
export * from './logger/SquizRemoteLogger';
|
|
9
|
+
export * from './logger/RemoteLogger';
|
|
10
|
+
export * from './logger/LoggerMessage';
|
|
11
|
+
export * from './logger/Logger';
|
|
12
|
+
export * from './httpClient/HttpRequestBuilder';
|
|
13
|
+
export * from './httpClient/HttpClient';
|
|
14
|
+
export * from './httpClient/FetchHttpClient';
|
|
15
|
+
export * from './exception/DomainException';
|
|
16
|
+
export * from './event/DynamoDBEventMapper';
|
|
17
|
+
export * from './event/DomainEvent';
|
|
18
|
+
export * from './event/AggregateRoot';
|
|
19
|
+
export * from './date/DateManipulator';
|
|
20
|
+
export * from './config/ConfigurationLoader';
|
|
21
|
+
export * from './cloudflare/ImplCloudflareKVHttpService';
|
|
22
|
+
export * from './cloudflare/CloudflareKVHttpService';
|
|
23
|
+
export * from './event/EventHandler';
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { injectable } from 'inversify';
|
|
2
|
+
import {
|
|
3
|
+
CreateScheduleCommand,
|
|
4
|
+
DeleteScheduleCommand,
|
|
5
|
+
FlexibleTimeWindowMode,
|
|
6
|
+
GetScheduleCommand,
|
|
7
|
+
ResourceNotFoundException,
|
|
8
|
+
SchedulerClient,
|
|
9
|
+
} from '@aws-sdk/client-scheduler';
|
|
10
|
+
import { DomainEvent } from '../event/DomainEvent';
|
|
11
|
+
import { PutItemCommandInput } from '@aws-sdk/client-dynamodb';
|
|
12
|
+
import { eventToDynamoDB } from '../event/DynamoDBEventMapper';
|
|
13
|
+
import { randomUUID } from 'crypto';
|
|
14
|
+
import {
|
|
15
|
+
ScheduleName,
|
|
16
|
+
Scheduler,
|
|
17
|
+
SchedulerOptions,
|
|
18
|
+
} from '../scheduler/Scheduler';
|
|
19
|
+
import { Logger } from '../logger/Logger';
|
|
20
|
+
import { createLog } from '../logger/LoggerMessage';
|
|
21
|
+
import { marshall } from '@aws-sdk/util-dynamodb';
|
|
22
|
+
|
|
23
|
+
export type EventBridgeSchedulerConfig = {
|
|
24
|
+
region: string;
|
|
25
|
+
groupName: string;
|
|
26
|
+
eventTableName: string;
|
|
27
|
+
schedulerRole: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
@injectable()
|
|
31
|
+
export class EventBridgeScheduler implements Scheduler {
|
|
32
|
+
constructor(
|
|
33
|
+
private readonly config: EventBridgeSchedulerConfig,
|
|
34
|
+
private readonly client: SchedulerClient,
|
|
35
|
+
private readonly logger: Logger,
|
|
36
|
+
) {}
|
|
37
|
+
|
|
38
|
+
async schedule(
|
|
39
|
+
domainEvent: DomainEvent,
|
|
40
|
+
options: SchedulerOptions,
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
const logMessage = createLog()
|
|
43
|
+
.attachEventName(domainEvent.name)
|
|
44
|
+
.create(this);
|
|
45
|
+
|
|
46
|
+
this.logger.debug(logMessage('started scheduling'));
|
|
47
|
+
// I putted here "the schedule attributes" because in that way we ensure that every PutItem command
|
|
48
|
+
// it will create always a new record in dynamoDB
|
|
49
|
+
const putItemCommand: PutItemCommandInput = {
|
|
50
|
+
TableName: this.config.eventTableName,
|
|
51
|
+
Item: {
|
|
52
|
+
...eventToDynamoDB(domainEvent),
|
|
53
|
+
// https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-schedule-context-attributes.html
|
|
54
|
+
...marshall({
|
|
55
|
+
eventId: '<aws.scheduler.execution-id>',
|
|
56
|
+
time: '<aws.scheduler.scheduled-time>',
|
|
57
|
+
}),
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
this.logger.debug(...logMessage('finished mapping to PutItemCommandInput'));
|
|
62
|
+
|
|
63
|
+
const scheduleName = this.createScheduleName(options.name);
|
|
64
|
+
const scheduleExpression = this.createScheduleExpression(options);
|
|
65
|
+
|
|
66
|
+
this.logger.debug(
|
|
67
|
+
...logMessage(
|
|
68
|
+
`started calling AWS Scheduler with ScheduleName: ` +
|
|
69
|
+
`${scheduleName}, ScheduleExpression: ${scheduleExpression}`,
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
await this._deleteSchedule(scheduleName, logMessage);
|
|
73
|
+
const command = new CreateScheduleCommand({
|
|
74
|
+
Name: scheduleName,
|
|
75
|
+
GroupName: this.config.groupName,
|
|
76
|
+
ScheduleExpression: scheduleExpression,
|
|
77
|
+
ScheduleExpressionTimezone: 'UTC',
|
|
78
|
+
State: 'ENABLED',
|
|
79
|
+
FlexibleTimeWindow: {
|
|
80
|
+
Mode: FlexibleTimeWindowMode.OFF,
|
|
81
|
+
},
|
|
82
|
+
ActionAfterCompletion: 'DELETE',
|
|
83
|
+
Target: {
|
|
84
|
+
Arn: 'arn:aws:scheduler:::aws-sdk:dynamodb:putItem',
|
|
85
|
+
Input: JSON.stringify(putItemCommand),
|
|
86
|
+
RoleArn: this.config.schedulerRole,
|
|
87
|
+
},
|
|
88
|
+
ClientToken: randomUUID(),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await this.client.send(command);
|
|
92
|
+
this.logger.debug(...logMessage('finished calling AWS Scheduler'));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private createScheduleName(scheduleName: ScheduleName): string {
|
|
96
|
+
const truncateString = (str: string, maxLength: number): string =>
|
|
97
|
+
str.length > maxLength ? str.substring(0, maxLength) : str;
|
|
98
|
+
const maxLengthOfScheduleName = 64;
|
|
99
|
+
|
|
100
|
+
return truncateString(scheduleName, maxLengthOfScheduleName);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private createScheduleExpression(options: SchedulerOptions): string {
|
|
104
|
+
switch (options.type) {
|
|
105
|
+
case 'at': {
|
|
106
|
+
const dateString = options.value.toISOString().replace(/\..*/, '');
|
|
107
|
+
|
|
108
|
+
return `at(${dateString})`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
case 'cron':
|
|
112
|
+
return `cron(${options.value})`;
|
|
113
|
+
case 'rate':
|
|
114
|
+
return `rate(${options.value} ${options.unit})`;
|
|
115
|
+
default:
|
|
116
|
+
throw new Error(`Passed unresolved ScheduleOption type.`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async deleteSchedule(scheduleName: ScheduleName): Promise<void> {
|
|
121
|
+
const logMessage = createLog()
|
|
122
|
+
.attachMetadata({ scheduleName })
|
|
123
|
+
.create(this);
|
|
124
|
+
|
|
125
|
+
return this._deleteSchedule(scheduleName, logMessage);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private async _deleteSchedule(
|
|
129
|
+
scheduleName: ScheduleName,
|
|
130
|
+
logMessage: (message: string) => [string, Record<string, unknown>],
|
|
131
|
+
): Promise<void> {
|
|
132
|
+
const trimmedScheduleName = this.createScheduleName(scheduleName);
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
this.logger.debug(
|
|
136
|
+
...logMessage(
|
|
137
|
+
`started getting schedule, scheduleName: ${trimmedScheduleName}`,
|
|
138
|
+
),
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const getCommand = new GetScheduleCommand({
|
|
142
|
+
GroupName: this.config.groupName,
|
|
143
|
+
Name: trimmedScheduleName,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
await this.client.send(getCommand);
|
|
147
|
+
|
|
148
|
+
this.logger.debug(
|
|
149
|
+
logMessage(
|
|
150
|
+
`finished getting schedule, scheduleName: ${trimmedScheduleName}`,
|
|
151
|
+
),
|
|
152
|
+
);
|
|
153
|
+
} catch (e) {
|
|
154
|
+
if (e instanceof ResourceNotFoundException) {
|
|
155
|
+
this.logger.debug(
|
|
156
|
+
...logMessage(
|
|
157
|
+
`the schedule does not exist, skipped deleting existing schedule, scheduleName: ${trimmedScheduleName}`,
|
|
158
|
+
),
|
|
159
|
+
);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
throw e;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.logger.debug(...logMessage('started deleting schedule'));
|
|
167
|
+
|
|
168
|
+
const deleteCommand = new DeleteScheduleCommand({
|
|
169
|
+
GroupName: this.config.groupName,
|
|
170
|
+
Name: trimmedScheduleName,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await this.client.send(deleteCommand);
|
|
174
|
+
|
|
175
|
+
this.logger.debug(...logMessage('finished deleting schedule'));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DomainEvent } from './../event/DomainEvent';
|
|
2
|
+
import { injectable } from 'inversify';
|
|
3
|
+
|
|
4
|
+
export type CronExpression =
|
|
5
|
+
`${string} ${string} ${string} ${string} ${string} ${string}`;
|
|
6
|
+
export type RateUnit = 'minutes' | 'hours' | 'days';
|
|
7
|
+
export type ScheduleName = string;
|
|
8
|
+
export type SchedulerOptions = (
|
|
9
|
+
| {
|
|
10
|
+
type: 'at';
|
|
11
|
+
value: Date;
|
|
12
|
+
}
|
|
13
|
+
| {
|
|
14
|
+
type: 'cron';
|
|
15
|
+
value: CronExpression;
|
|
16
|
+
}
|
|
17
|
+
| {
|
|
18
|
+
type: 'rate';
|
|
19
|
+
value: number;
|
|
20
|
+
unit: RateUnit;
|
|
21
|
+
}
|
|
22
|
+
) & { name: ScheduleName };
|
|
23
|
+
|
|
24
|
+
@injectable()
|
|
25
|
+
export abstract class Scheduler {
|
|
26
|
+
abstract schedule(
|
|
27
|
+
domainEvent: DomainEvent,
|
|
28
|
+
options: SchedulerOptions,
|
|
29
|
+
): Promise<void>;
|
|
30
|
+
|
|
31
|
+
abstract deleteSchedule(scheduleName: ScheduleName): Promise<void>;
|
|
32
|
+
}
|