@squiz/job-runner-lib 2.3.0 → 2.4.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/CHANGELOG.md +6 -0
- package/lib/domains/component/errors/JobError.spec.d.ts +1 -0
- package/lib/domains/job/ParsePartitionKey/ParsePartitionKey.d.ts +2 -2
- package/lib/domains/job/ParsePartitionKey/ParsePartitionKey.types.d.ts +5 -0
- package/lib/domains/job/S3Repository/JobDetailsRepository.d.ts +1 -2
- package/lib/domains/job/S3Repository/JobDetailsRepository.spec.d.ts +1 -1
- package/lib/domains/job/S3Repository/JobUploadsRepository.d.ts +16 -0
- package/lib/domains/job/{services/JobQueueService/JobQueueService.spec.d.ts → S3Repository/JobUploadsRepository.spec.d.ts} +1 -1
- package/lib/domains/job/S3Repository/S3RepositoryBase.d.ts +12 -5
- package/lib/domains/job/S3Repository/index.d.ts +2 -1
- package/lib/domains/job/constants/InjectTokens.d.ts +8 -0
- package/lib/domains/job/constants/JobExecutionStatus.constants.d.ts +2 -1
- package/lib/domains/job/constants/Repository.constants.d.ts +3 -3
- package/lib/domains/job/constants/RetryConfig.constants.d.ts +21 -0
- package/lib/domains/job/index.d.ts +6 -4
- package/lib/domains/job/manifest/JobManifestTypes.d.ts +7 -6
- package/lib/domains/job/model/Base/Base.d.ts +10 -5
- package/lib/domains/job/model/Job/Job.d.ts +9 -6
- package/lib/domains/job/model/JobContext/JobContext.d.ts +6 -5
- package/lib/domains/job/model/JobExecution/JobExecution.d.ts +64 -9
- package/lib/domains/job/model/LogPayload/LogPayload.d.ts +21 -12
- package/lib/domains/job/model/LogPayload/index.d.ts +1 -0
- package/lib/domains/job/model/LogPayload/mocks/LogPayload.mock.d.ts +6 -0
- package/lib/domains/job/repository/AbstractRepository.d.ts +20 -11
- package/lib/domains/job/repository/JobContextRepository/JobContextRepository.d.ts +6 -7
- package/lib/domains/job/repository/JobExecutionRepository/JobExecutionRepository.d.ts +7 -17
- package/lib/domains/job/repository/JobExecutionRepository/JobExecutionRepository.spec.d.ts +1 -1
- package/lib/domains/job/repository/JobExecutionRepository/utils/convertDynamoDbItemToJobExecution/convertDynamoDbItemToJobExecution.d.ts +2 -0
- package/lib/domains/job/repository/JobExecutionRepository/utils/index.d.ts +1 -0
- package/lib/domains/job/repository/JobManifestRepository/JobManifestRepository.d.ts +5 -6
- package/lib/domains/job/repository/JobRepository/JobRepository.d.ts +6 -7
- package/lib/domains/job/repository/MultiTenantJobExecutionRepository/MultiTenantJobExecutionRepository.d.ts +9 -0
- package/lib/domains/job/repository/MultiTenantJobExecutionRepository/MultiTenantJobExecutionRepository.spec.d.ts +1 -0
- package/lib/domains/job/repository/index.d.ts +1 -0
- package/lib/domains/job/services/JobContextService/JobContextService.d.ts +6 -3
- package/lib/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.d.ts +10 -6
- package/lib/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.defs.d.ts +1 -3
- package/lib/domains/job/services/JobManifestService/JobManifestService.d.ts +0 -1
- package/lib/domains/job/services/JobStartQueueService/JobStartQueueService.d.ts +17 -0
- package/lib/domains/job/services/JobStartQueueService/JobStartQueueService.defs.d.ts +25 -0
- package/lib/domains/job/services/JobUploadService/utils/manifestValidator.d.ts +1 -2
- package/lib/domains/job/services/index.d.ts +2 -1
- package/lib/domains/manifest/services/ManifestServiceForDev.d.ts +0 -3
- package/lib/index.d.ts +1 -0
- package/lib/index.js +13 -13
- package/lib/index.js.map +4 -4
- package/lib/jest-global-setup.d.ts +6 -1
- package/lib/mocks/mockIoc.d.ts +3 -3
- package/lib/utils/buildJobRunnerModule/buildJobRunnerModule.d.ts +2 -0
- package/lib/utils/buildJobRunnerModule/buildJobRunnerModule.types.d.ts +14 -0
- package/lib/utils/index.d.ts +2 -0
- package/package.json +12 -11
- package/src/domains/component/errors/JobError.spec.ts +30 -0
- package/src/domains/component/errors/JobError.ts +8 -1
- package/src/domains/job/ParsePartitionKey/ParsePartitionKey.spec.ts +17 -8
- package/src/domains/job/ParsePartitionKey/ParsePartitionKey.ts +13 -16
- package/src/domains/job/ParsePartitionKey/ParsePartitionKey.types.ts +6 -0
- package/src/domains/job/S3Repository/JobDetailsRepository.spec.ts +47 -31
- package/src/domains/job/S3Repository/JobDetailsRepository.ts +7 -8
- package/src/domains/job/S3Repository/JobUploadsRepository.spec.ts +66 -0
- package/src/domains/job/S3Repository/JobUploadsRepository.ts +35 -0
- package/src/domains/job/S3Repository/S3RepositoryBase.spec.ts +13 -19
- package/src/domains/job/S3Repository/S3RepositoryBase.ts +24 -9
- package/src/domains/job/S3Repository/index.ts +2 -1
- package/src/domains/job/constants/InjectTokens.ts +8 -0
- package/src/domains/job/constants/JobExecutionStatus.constants.ts +1 -0
- package/src/domains/job/constants/Repository.constants.ts +3 -3
- package/src/domains/job/constants/RetryConfig.constants.ts +29 -0
- package/src/domains/job/core/pagination/services/PaginationService.spec.ts +3 -5
- package/src/domains/job/index.ts +6 -4
- package/src/domains/job/manifest/JobManifestTypes.ts +8 -6
- package/src/domains/job/manifest/mocks/JobManifest.mock.ts +2 -2
- package/src/domains/job/manifest/mocks/JobManifestDto.mock.ts +3 -2
- package/src/domains/job/manifest/mocks/JobManifestRecord.mock.ts +4 -3
- package/src/domains/job/model/Base/Base.ts +11 -5
- package/src/domains/job/model/Job/Job.ts +11 -6
- package/src/domains/job/model/Job/mocks/Job.mock.ts +2 -2
- package/src/domains/job/model/Job/mocks/JobDto.mock.ts +3 -2
- package/src/domains/job/model/Job/mocks/JobRecord.mock.ts +3 -2
- package/src/domains/job/model/JobContext/JobContext.ts +7 -5
- package/src/domains/job/model/JobContext/mocks/JobContext.mock.ts +2 -2
- package/src/domains/job/model/JobContext/mocks/JobContextDto.mock.ts +3 -2
- package/src/domains/job/model/JobContext/mocks/JobContextRecord.mock.ts +3 -2
- package/src/domains/job/model/JobExecution/JobExecution.ts +74 -9
- package/src/domains/job/model/JobExecution/mocks/JobExecution.mock.ts +7 -4
- package/src/domains/job/model/JobExecution/mocks/JobExecutionDto.mock.ts +32 -16
- package/src/domains/job/model/JobExecution/mocks/JobExecutionRecord.mock.ts +10 -4
- package/src/domains/job/model/LogPayload/LogPayload.ts +32 -11
- package/src/domains/job/model/LogPayload/index.ts +1 -0
- package/src/domains/job/model/LogPayload/mocks/LogPayload.mock.ts +21 -0
- package/src/domains/job/repository/AbstractRepository.ts +91 -59
- package/src/domains/job/repository/JobContextRepository/JobContextRepository.spec.ts +39 -49
- package/src/domains/job/repository/JobContextRepository/JobContextRepository.ts +33 -21
- package/src/domains/job/repository/JobExecutionRepository/JobExecutionRepository.spec.ts +343 -169
- package/src/domains/job/repository/JobExecutionRepository/JobExecutionRepository.ts +112 -141
- package/src/domains/job/repository/JobExecutionRepository/utils/convertDynamoDbItemToJobExecution/convertDynamoDbItemToJobExecution.ts +22 -0
- package/src/domains/job/repository/JobExecutionRepository/utils/index.ts +1 -0
- package/src/domains/job/repository/JobManifestRepository/JobManifestRepository.spec.ts +23 -38
- package/src/domains/job/repository/JobManifestRepository/JobManifestRepository.ts +29 -36
- package/src/domains/job/repository/JobRepository/JobRepository.spec.ts +72 -80
- package/src/domains/job/repository/JobRepository/JobRepository.ts +66 -70
- package/src/domains/job/repository/MultiTenantJobExecutionRepository/MultiTenantJobExecutionRepository.spec.ts +60 -0
- package/src/domains/job/repository/MultiTenantJobExecutionRepository/MultiTenantJobExecutionRepository.ts +42 -0
- package/src/domains/job/repository/index.ts +1 -0
- package/src/domains/job/services/JobContextService/JobContextService.spec.ts +73 -39
- package/src/domains/job/services/JobContextService/JobContextService.ts +37 -6
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.defs.ts +1 -3
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.spec.ts +113 -31
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.ts +101 -49
- package/src/domains/job/services/JobManifestService/JobManifestService.spec.ts +4 -41
- package/src/domains/job/services/JobManifestService/JobManifestService.ts +2 -8
- package/src/domains/job/services/JobStartQueueService/JobStartQueueService.defs.ts +27 -0
- package/src/domains/job/services/JobStartQueueService/JobStartQueueService.ts +42 -0
- package/src/domains/job/services/JobUploadService/JobUploadService.spec.ts +1 -1
- package/src/domains/job/services/JobUploadService/JobUploadService.ts +1 -1
- package/src/domains/job/services/JobUploadService/utils/manifestValidator.spec.ts +12 -25
- package/src/domains/job/services/JobUploadService/utils/manifestValidator.ts +2 -7
- package/src/domains/job/services/index.ts +2 -1
- package/src/domains/job/utils/SlackClient/SlackClient.spec.ts +0 -2
- package/src/domains/manifest/services/ManifestServiceForDev.spec.ts +1 -2
- package/src/domains/manifest/services/ManifestServiceForDev.ts +0 -4
- package/src/index.ts +1 -0
- package/src/jest-global-setup.ts +8 -4
- package/src/mocks/mockIoc.ts +18 -43
- package/src/utils/buildJobRunnerModule/buildJobRunnerModule.ts +81 -0
- package/src/utils/buildJobRunnerModule/buildJobRunnerModule.types.ts +13 -0
- package/src/utils/index.ts +2 -0
- package/lib/domains/job/S3Repository/S3Repository.d.ts +0 -15
- package/lib/domains/job/S3Repository/S3Repository.spec.d.ts +0 -5
- package/lib/domains/job/services/JobQueueService/JobQueueService.d.ts +0 -9
- package/lib/domains/job/services/JobQueueService/JobQueueService.defs.d.ts +0 -9
- package/src/custom-types.d.ts +0 -7
- package/src/domains/job/S3Repository/S3Repository.spec.ts +0 -50
- package/src/domains/job/S3Repository/S3Repository.ts +0 -27
- package/src/domains/job/services/JobQueueService/JobQueueService.defs.ts +0 -10
- package/src/domains/job/services/JobQueueService/JobQueueService.spec.ts +0 -190
- package/src/domains/job/services/JobQueueService/JobQueueService.ts +0 -60
package/src/mocks/mockIoc.ts
CHANGED
|
@@ -1,52 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { Logger } from '@squiz/optimization-logger';
|
|
3
|
+
import { Container } from 'inversify';
|
|
3
4
|
import { buildProviderModule } from 'inversify-binding-decorators';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import { Logger } from '@squiz/dx-logger-lib';
|
|
7
|
-
import { S3Client } from '@aws-sdk/client-s3';
|
|
8
|
-
|
|
9
|
-
// Makes tsoa's Controller injectable
|
|
10
|
-
decorate(injectable(), Controller);
|
|
5
|
+
import { testLogger } from '../jest-global-setup';
|
|
6
|
+
import { buildJobRunnerModule } from '../utils';
|
|
11
7
|
|
|
12
8
|
let iocContainer: Container;
|
|
13
9
|
|
|
14
|
-
function initIocContainer(
|
|
10
|
+
function initIocContainer(logger?: Logger): void {
|
|
11
|
+
const tenant = faker.string.uuid();
|
|
12
|
+
const jobRunnerModule = buildJobRunnerModule({
|
|
13
|
+
local: true,
|
|
14
|
+
dynamoTableName: faker.lorem.words(),
|
|
15
|
+
jobUploadsBucket: faker.lorem.words(),
|
|
16
|
+
jobDetailsBucket: faker.lorem.words(),
|
|
17
|
+
awsRegion: faker.lorem.words(),
|
|
18
|
+
});
|
|
19
|
+
|
|
15
20
|
// Create a new container tsoa can use
|
|
16
|
-
iocContainer = new Container();
|
|
21
|
+
iocContainer = new Container({ skipBaseClassChecks: true });
|
|
17
22
|
|
|
18
23
|
// make inversify aware of inversify-binding-decorators
|
|
19
24
|
iocContainer.load(buildProviderModule());
|
|
20
|
-
|
|
21
|
-
// Init DynamoDB and S3 clients
|
|
22
|
-
let dynamoDbClient: DynamoDBClient;
|
|
23
|
-
let s3Client: S3Client;
|
|
24
|
-
|
|
25
|
-
if (process.env.ENVIRONMENT !== 'local') {
|
|
26
|
-
dynamoDbClient = new DynamoDBClient({ region: 'ap-southeast-2' });
|
|
27
|
-
s3Client = new S3Client({ region: 'ap-southeast-2' });
|
|
28
|
-
} else {
|
|
29
|
-
// eslint-disable-next-line no-console
|
|
30
|
-
console.log(`environment: '${process.env.ENVIRONMENT}'`);
|
|
31
|
-
|
|
32
|
-
// eslint-disable-next-line no-console
|
|
33
|
-
console.log(`table: '${process.env.DYNAMODB_TABLE}'`);
|
|
34
|
-
dynamoDbClient = new DynamoDBClient({
|
|
35
|
-
credentials: { accessKeyId: 'key', secretAccessKey: 'key' },
|
|
36
|
-
endpoint: 'http://localhost:8000',
|
|
37
|
-
});
|
|
38
|
-
s3Client = new S3Client({
|
|
39
|
-
credentials: { accessKeyId: 'key', secretAccessKey: 'key' },
|
|
40
|
-
endpoint: 'http://localhost:8000',
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
iocContainer.bind<DynamoDBClient>(DynamoDBClient).toConstantValue(dynamoDbClient);
|
|
45
|
-
iocContainer.bind<Logger>('Logger').toConstantValue(log);
|
|
46
|
-
iocContainer.bind<S3Client>(S3Client).toConstantValue(s3Client);
|
|
47
|
-
|
|
48
|
-
iocContainer.bind<string>('JobDetailsBucketName').toConstantValue('configObj.jobDetailsBucketName');
|
|
49
|
-
iocContainer.bind<string>('S3RepositoryBucketName').toConstantValue('configObj.bucketName');
|
|
25
|
+
iocContainer.load(jobRunnerModule({ tenant, logger: logger || testLogger }));
|
|
50
26
|
}
|
|
51
|
-
|
|
52
|
-
export { iocContainer, initIocContainer };
|
|
27
|
+
export { initIocContainer, iocContainer };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
2
|
+
import { ECSClient } from '@aws-sdk/client-ecs';
|
|
3
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
4
|
+
import { SQSClient } from '@aws-sdk/client-sqs';
|
|
5
|
+
import { Logger } from '@squiz/optimization-logger';
|
|
6
|
+
import { ContainerModule, interfaces } from 'inversify';
|
|
7
|
+
import {
|
|
8
|
+
InjectTokens,
|
|
9
|
+
JobContextService,
|
|
10
|
+
JobDetailsRepository,
|
|
11
|
+
JobExecutionRepository,
|
|
12
|
+
JobExecutionTaskService,
|
|
13
|
+
JobManifestService,
|
|
14
|
+
JobStartQueueService,
|
|
15
|
+
JobUploadsRepository,
|
|
16
|
+
} from '../../domains/job';
|
|
17
|
+
import { CreateJobRunnerModuleProps, CreateJobRunnerModuleResult } from './buildJobRunnerModule.types';
|
|
18
|
+
|
|
19
|
+
export const buildJobRunnerModule = (props: CreateJobRunnerModuleProps): CreateJobRunnerModuleResult => {
|
|
20
|
+
let dynamoDbClient: DynamoDBClient;
|
|
21
|
+
let s3Client: S3Client;
|
|
22
|
+
let ecsClient: ECSClient;
|
|
23
|
+
let sqsClient: SQSClient;
|
|
24
|
+
|
|
25
|
+
if (props.local) {
|
|
26
|
+
dynamoDbClient = new DynamoDBClient({
|
|
27
|
+
credentials: { accessKeyId: 'key', secretAccessKey: 'key' },
|
|
28
|
+
endpoint: 'http://localhost:8000',
|
|
29
|
+
});
|
|
30
|
+
s3Client = new S3Client({
|
|
31
|
+
credentials: { accessKeyId: 'key', secretAccessKey: 'key' },
|
|
32
|
+
endpoint: 'http://localhost:4566', // This is the localstack EDGE_PORT
|
|
33
|
+
forcePathStyle: true,
|
|
34
|
+
});
|
|
35
|
+
ecsClient = new ECSClient({});
|
|
36
|
+
sqsClient = new SQSClient({
|
|
37
|
+
credentials: { accessKeyId: 'key', secretAccessKey: 'key' },
|
|
38
|
+
endpoint: 'http://localhost:4566',
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
dynamoDbClient = new DynamoDBClient({ region: props.awsRegion });
|
|
42
|
+
s3Client = new S3Client({ region: props.awsRegion });
|
|
43
|
+
ecsClient = new ECSClient({ region: props.awsRegion });
|
|
44
|
+
sqsClient = new SQSClient({ region: props.awsRegion });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return ({ tenant, logger }: { tenant?: string; logger: Logger }) => {
|
|
48
|
+
return new ContainerModule((bind: interfaces.Bind) => {
|
|
49
|
+
bind(DynamoDBClient).toConstantValue(dynamoDbClient);
|
|
50
|
+
bind(S3Client).toConstantValue(s3Client);
|
|
51
|
+
bind(ECSClient).toConstantValue(ecsClient);
|
|
52
|
+
bind(SQSClient).toConstantValue(sqsClient);
|
|
53
|
+
|
|
54
|
+
bind(InjectTokens.Logger).toConstantValue(logger);
|
|
55
|
+
bind(InjectTokens.Tenant).toConstantValue(tenant);
|
|
56
|
+
bind(InjectTokens.DynamoTableName).toConstantValue(props.dynamoTableName);
|
|
57
|
+
bind(InjectTokens.JobUploadsBucket).toConstantValue(props.jobUploadsBucket);
|
|
58
|
+
bind(InjectTokens.JobDetailsBucket).toConstantValue(props.jobDetailsBucket);
|
|
59
|
+
|
|
60
|
+
if (props.jobStartQueueUrl) {
|
|
61
|
+
bind(InjectTokens.JobStartQueueUrl).toConstantValue(props.jobStartQueueUrl);
|
|
62
|
+
bind<JobStartQueueService>(JobStartQueueService).toDynamicValue(
|
|
63
|
+
(context: interfaces.Context) =>
|
|
64
|
+
new JobStartQueueService(sqsClient, context.container.get(InjectTokens.JobStartQueueUrl)),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
bind<JobExecutionTaskService>(JobExecutionTaskService).toDynamicValue(
|
|
69
|
+
(context: interfaces.Context) =>
|
|
70
|
+
new JobExecutionTaskService(
|
|
71
|
+
ecsClient,
|
|
72
|
+
context.container.get(JobManifestService),
|
|
73
|
+
context.container.get(JobContextService),
|
|
74
|
+
context.container.get(JobExecutionRepository),
|
|
75
|
+
context.container.get(JobDetailsRepository),
|
|
76
|
+
context.container.get(JobUploadsRepository),
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Logger } from '@squiz/optimization-logger';
|
|
2
|
+
import { ContainerModule } from 'inversify';
|
|
3
|
+
|
|
4
|
+
export type CreateJobRunnerModuleProps = {
|
|
5
|
+
dynamoTableName: string;
|
|
6
|
+
jobUploadsBucket: string;
|
|
7
|
+
jobDetailsBucket: string;
|
|
8
|
+
awsRegion: string;
|
|
9
|
+
local: boolean;
|
|
10
|
+
jobStartQueueUrl?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type CreateJobRunnerModuleResult = (props: { tenant?: string; logger: Logger }) => ContainerModule;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright Squiz Australia Pty Ltd. All Rights Reserved.
|
|
4
|
-
*/
|
|
5
|
-
import { S3Client } from '@aws-sdk/client-s3';
|
|
6
|
-
import { S3RepositoryBase } from './S3RepositoryBase';
|
|
7
|
-
/**
|
|
8
|
-
* Repository class for interacting with S3.
|
|
9
|
-
* @export
|
|
10
|
-
* @class S3Repository
|
|
11
|
-
*/
|
|
12
|
-
export declare class S3Repository extends S3RepositoryBase {
|
|
13
|
-
protected s3Client: S3Client;
|
|
14
|
-
constructor(s3Client: S3Client, bucketName: string);
|
|
15
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { JobExecutionTaskService } from '../JobExecutionTaskService/JobExecutionTaskService';
|
|
2
|
-
import { CheckAndStartQueuedJobTaskParams } from './JobQueueService.defs';
|
|
3
|
-
import { JobExecutionRepository } from '../../repository';
|
|
4
|
-
export declare class JobQueueService {
|
|
5
|
-
private readonly jobExecutionTaskService;
|
|
6
|
-
private readonly jobExecutionRepository;
|
|
7
|
-
constructor(jobExecutionTaskService: JobExecutionTaskService, jobExecutionRepository: JobExecutionRepository);
|
|
8
|
-
checkAndStartQueuedJob(params: CheckAndStartQueuedJobTaskParams): Promise<string | null>;
|
|
9
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { RunJobTaskParams } from '../JobExecutionTaskService/JobExecutionTaskService.defs';
|
|
2
|
-
/**
|
|
3
|
-
* The parameters required for running a job as an ECS task.
|
|
4
|
-
*/
|
|
5
|
-
export interface CheckAndStartQueuedJobTaskParams extends Omit<RunJobTaskParams, 'jobExecution'> {
|
|
6
|
-
jobName: string;
|
|
7
|
-
runtimeTaskFamily: string;
|
|
8
|
-
maxTenantConcurrentTasks: number;
|
|
9
|
-
}
|
package/src/custom-types.d.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright Squiz Australia Pty Ltd. All Rights Reserved.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { S3Client, S3ClientConfig } from '@aws-sdk/client-s3';
|
|
7
|
-
import { S3Repository } from './S3Repository';
|
|
8
|
-
import { initIocContainer, iocContainer } from '../../../mocks/mockIoc';
|
|
9
|
-
import { testLogger } from '../../../jest-global-setup';
|
|
10
|
-
|
|
11
|
-
// Create a new container tsoa can use
|
|
12
|
-
initIocContainer(testLogger);
|
|
13
|
-
|
|
14
|
-
// Mock S3 Client
|
|
15
|
-
const mockOptions = {} as S3ClientConfig;
|
|
16
|
-
const mockClient = new S3Client(mockOptions);
|
|
17
|
-
|
|
18
|
-
const mockSend = jest.fn().mockResolvedValue({
|
|
19
|
-
Body: { transformToString: jest.fn().mockResolvedValue('file') },
|
|
20
|
-
$metadata: {},
|
|
21
|
-
});
|
|
22
|
-
mockClient.send = mockSend;
|
|
23
|
-
|
|
24
|
-
// Inject the S3Repository with a mocked client
|
|
25
|
-
iocContainer.rebind<S3Client>(S3Client).toConstantValue(mockClient);
|
|
26
|
-
|
|
27
|
-
let s3Repository: S3Repository;
|
|
28
|
-
|
|
29
|
-
describe('S3Repository', (): void => {
|
|
30
|
-
beforeAll((): void => {
|
|
31
|
-
s3Repository = iocContainer.get(S3Repository);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe(`get`, (): void => {
|
|
35
|
-
beforeEach(() => {
|
|
36
|
-
jest.resetAllMocks();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it(`should return a response for get`, async (): Promise<void> => {
|
|
40
|
-
const mockKey = `mock`;
|
|
41
|
-
mockSend.mockResolvedValueOnce({
|
|
42
|
-
Body: { transformToString: jest.fn().mockResolvedValue('file') },
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const response = await s3Repository.get(mockKey);
|
|
46
|
-
expect(mockSend).toBeCalledTimes(1);
|
|
47
|
-
expect(response).toStrictEqual('file');
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
});
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright Squiz Australia Pty Ltd. All Rights Reserved.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as dotenv from 'dotenv';
|
|
7
|
-
dotenv.config();
|
|
8
|
-
|
|
9
|
-
import { S3Client } from '@aws-sdk/client-s3';
|
|
10
|
-
import { inject } from 'inversify';
|
|
11
|
-
import { S3RepositoryBase } from './S3RepositoryBase';
|
|
12
|
-
import { provideTransient } from '../transientProvider';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Repository class for interacting with S3.
|
|
16
|
-
* @export
|
|
17
|
-
* @class S3Repository
|
|
18
|
-
*/
|
|
19
|
-
@provideTransient(S3Repository)
|
|
20
|
-
export class S3Repository extends S3RepositoryBase {
|
|
21
|
-
public constructor(
|
|
22
|
-
@inject(S3Client) protected s3Client: S3Client,
|
|
23
|
-
@inject('S3RepositoryBucketName') bucketName: string,
|
|
24
|
-
) {
|
|
25
|
-
super(s3Client, bucketName);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { RunJobTaskParams } from '../JobExecutionTaskService/JobExecutionTaskService.defs';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The parameters required for running a job as an ECS task.
|
|
5
|
-
*/
|
|
6
|
-
export interface CheckAndStartQueuedJobTaskParams extends Omit<RunJobTaskParams, 'jobExecution'> {
|
|
7
|
-
jobName: string;
|
|
8
|
-
runtimeTaskFamily: string;
|
|
9
|
-
maxTenantConcurrentTasks: number;
|
|
10
|
-
}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright Squiz Australia Pty Ltd. All Rights Reserved.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { ECSClient } from '@aws-sdk/client-ecs';
|
|
7
|
-
import { faker } from '@faker-js/faker/locale/en';
|
|
8
|
-
import { S3Client } from '@aws-sdk/client-s3';
|
|
9
|
-
import { JobContextRepository, JobExecutionRepository, JobManifestRepository } from '../../repository';
|
|
10
|
-
import { JobContextService } from '../JobContextService/JobContextService';
|
|
11
|
-
import { JobManifestService } from '../JobManifestService/JobManifestService';
|
|
12
|
-
import { JobQueueService } from './JobQueueService';
|
|
13
|
-
import { JobExecutionTaskService } from '../JobExecutionTaskService/JobExecutionTaskService';
|
|
14
|
-
import { PaginationService } from '../../core/pagination';
|
|
15
|
-
import { JobExecution } from '../../model/JobExecution';
|
|
16
|
-
import { JOB_EXECUTION_STATUS } from '../../constants/JobExecutionStatus.constants';
|
|
17
|
-
import { createMockJobManifest } from '../../manifest';
|
|
18
|
-
import { createMockJobContext } from '../../model/JobContext';
|
|
19
|
-
import { CheckAndStartQueuedJobTaskParams } from './JobQueueService.defs';
|
|
20
|
-
import { JobDetailsRepository, S3Repository } from '../../S3Repository';
|
|
21
|
-
|
|
22
|
-
describe('JobQueueService', () => {
|
|
23
|
-
const mockJobDetailsBucketName = faker.lorem.word();
|
|
24
|
-
const mockJobUploadBucketName = faker.lorem.word();
|
|
25
|
-
const jobExecutionBase = {
|
|
26
|
-
context: ``,
|
|
27
|
-
ecsTaskId: ``,
|
|
28
|
-
input: ``,
|
|
29
|
-
jobName: `mockJobName`,
|
|
30
|
-
timeFinished: null,
|
|
31
|
-
timeStarted: null,
|
|
32
|
-
type: 'jobExecution',
|
|
33
|
-
version: '1.2.3',
|
|
34
|
-
};
|
|
35
|
-
const mockExecutionOld: JobExecution = {
|
|
36
|
-
...jobExecutionBase,
|
|
37
|
-
id: 'old',
|
|
38
|
-
status: JOB_EXECUTION_STATUS.queued,
|
|
39
|
-
timeQueued: faker.date.past().toISOString(),
|
|
40
|
-
};
|
|
41
|
-
const mockExecutionNew: JobExecution = {
|
|
42
|
-
...jobExecutionBase,
|
|
43
|
-
id: 'new',
|
|
44
|
-
status: JOB_EXECUTION_STATUS.queued,
|
|
45
|
-
timeQueued: faker.date.future().toISOString(),
|
|
46
|
-
};
|
|
47
|
-
const mockCheckAndStartQueuedJobParams: CheckAndStartQueuedJobTaskParams = {
|
|
48
|
-
jobName: faker.lorem.word(),
|
|
49
|
-
tenantId: faker.string.uuid(),
|
|
50
|
-
shortEnvironment: faker.lorem.word(),
|
|
51
|
-
awsRegion: faker.lorem.word(),
|
|
52
|
-
clusterArn: faker.lorem.word(),
|
|
53
|
-
subnets: [],
|
|
54
|
-
maxTenantConcurrentTasks: 20,
|
|
55
|
-
shortRegion: faker.lorem.word(),
|
|
56
|
-
runtimeTaskFamily: faker.lorem.word(),
|
|
57
|
-
taskDefinitionArn: faker.lorem.word(),
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
let mockJobExecutionRepository: jest.Mocked<JobExecutionRepository>;
|
|
61
|
-
let mockEcsClient: jest.Mocked<ECSClient>;
|
|
62
|
-
let mockS3Client: jest.Mocked<S3Client>;
|
|
63
|
-
|
|
64
|
-
let jobManifestService: JobManifestService;
|
|
65
|
-
let jobContextService: JobContextService;
|
|
66
|
-
let jobExecutionTaskService: JobExecutionTaskService;
|
|
67
|
-
let jobQueueService: JobQueueService;
|
|
68
|
-
let jobDetailsRepository: JobDetailsRepository;
|
|
69
|
-
let jobUploadRepository: S3Repository;
|
|
70
|
-
|
|
71
|
-
let mockJobContextRepository: JobContextRepository;
|
|
72
|
-
let mockJobManifestRepository: JobManifestRepository;
|
|
73
|
-
|
|
74
|
-
beforeEach(() => {
|
|
75
|
-
mockJobExecutionRepository = {
|
|
76
|
-
list: jest.fn(),
|
|
77
|
-
findOne: jest.fn(),
|
|
78
|
-
update: jest.fn(),
|
|
79
|
-
} as unknown as jest.Mocked<JobExecutionRepository>;
|
|
80
|
-
|
|
81
|
-
mockEcsClient = {
|
|
82
|
-
send: jest.fn(),
|
|
83
|
-
} as unknown as jest.Mocked<ECSClient>;
|
|
84
|
-
|
|
85
|
-
mockS3Client = {
|
|
86
|
-
send: jest.fn().mockResolvedValue({
|
|
87
|
-
Body: { transformToString: jest.fn().mockResolvedValue('file') },
|
|
88
|
-
$metadata: {},
|
|
89
|
-
}),
|
|
90
|
-
} as unknown as jest.Mocked<S3Client>;
|
|
91
|
-
|
|
92
|
-
jobDetailsRepository = new JobDetailsRepository(mockS3Client, mockJobDetailsBucketName);
|
|
93
|
-
jobUploadRepository = new S3Repository(mockS3Client, mockJobUploadBucketName);
|
|
94
|
-
|
|
95
|
-
mockJobContextRepository = {
|
|
96
|
-
findOne: jest.fn(),
|
|
97
|
-
} as unknown as jest.Mocked<JobContextRepository>;
|
|
98
|
-
jobContextService = new JobContextService(mockJobContextRepository, new PaginationService());
|
|
99
|
-
|
|
100
|
-
mockJobManifestRepository = {
|
|
101
|
-
findOne: jest.fn(),
|
|
102
|
-
} as unknown as jest.Mocked<JobManifestRepository>;
|
|
103
|
-
jobManifestService = new JobManifestService(mockJobManifestRepository);
|
|
104
|
-
|
|
105
|
-
jobExecutionTaskService = new JobExecutionTaskService(
|
|
106
|
-
mockEcsClient,
|
|
107
|
-
jobManifestService,
|
|
108
|
-
jobContextService,
|
|
109
|
-
jobDetailsRepository,
|
|
110
|
-
jobUploadRepository,
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
jobQueueService = new JobQueueService(jobExecutionTaskService, mockJobExecutionRepository);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe('checkAndStartQueuedJob', () => {
|
|
117
|
-
it('should not start any jobs if no pending executions exist', async (): Promise<void> => {
|
|
118
|
-
mockJobExecutionRepository.list.mockResolvedValue([]);
|
|
119
|
-
jest.spyOn(jobExecutionTaskService, `hasReachedMaxTenantConcurrency`).mockResolvedValueOnce(false);
|
|
120
|
-
jest.spyOn(jobExecutionTaskService, `runJobExecutionTask`).mockResolvedValueOnce('');
|
|
121
|
-
|
|
122
|
-
await jobQueueService.checkAndStartQueuedJob(mockCheckAndStartQueuedJobParams);
|
|
123
|
-
expect(jobExecutionTaskService.runJobExecutionTask).not.toBeCalled();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should start the oldest queued job', async (): Promise<void> => {
|
|
127
|
-
mockJobExecutionRepository.list
|
|
128
|
-
.mockResolvedValueOnce([mockExecutionNew, mockExecutionOld])
|
|
129
|
-
.mockResolvedValueOnce([mockExecutionOld, mockExecutionNew])
|
|
130
|
-
.mockResolvedValueOnce([mockExecutionOld, mockExecutionOld]);
|
|
131
|
-
|
|
132
|
-
jest
|
|
133
|
-
.spyOn(jobExecutionTaskService, `hasReachedMaxTenantConcurrency`)
|
|
134
|
-
.mockResolvedValueOnce(false)
|
|
135
|
-
.mockResolvedValueOnce(false)
|
|
136
|
-
.mockResolvedValueOnce(false);
|
|
137
|
-
|
|
138
|
-
jest.spyOn(jobExecutionTaskService, `runJobExecutionTask`).mockResolvedValue('');
|
|
139
|
-
|
|
140
|
-
await jobQueueService.checkAndStartQueuedJob(mockCheckAndStartQueuedJobParams);
|
|
141
|
-
expect(jobExecutionTaskService.runJobExecutionTask).toBeCalledTimes(1);
|
|
142
|
-
let executionStarted = (jobExecutionTaskService.runJobExecutionTask as jest.Mock).mock.calls[0][0];
|
|
143
|
-
expect(executionStarted.jobExecution).toBe(mockExecutionOld);
|
|
144
|
-
|
|
145
|
-
await jobQueueService.checkAndStartQueuedJob(mockCheckAndStartQueuedJobParams);
|
|
146
|
-
expect(jobExecutionTaskService.runJobExecutionTask).toBeCalledTimes(2);
|
|
147
|
-
executionStarted = (jobExecutionTaskService.runJobExecutionTask as jest.Mock).mock.calls[1][0];
|
|
148
|
-
expect(executionStarted.jobExecution).toBe(mockExecutionOld);
|
|
149
|
-
|
|
150
|
-
await jobQueueService.checkAndStartQueuedJob(mockCheckAndStartQueuedJobParams);
|
|
151
|
-
expect(jobExecutionTaskService.runJobExecutionTask).toBeCalledTimes(3);
|
|
152
|
-
executionStarted = (jobExecutionTaskService.runJobExecutionTask as jest.Mock).mock.calls[2][0];
|
|
153
|
-
expect(executionStarted.jobExecution).toBe(mockExecutionOld);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('should create job details file when file is not found', async (): Promise<void> => {
|
|
157
|
-
mockJobExecutionRepository.list.mockResolvedValue([mockExecutionOld]);
|
|
158
|
-
|
|
159
|
-
jest.spyOn(jobExecutionTaskService, `hasReachedMaxTenantConcurrency`).mockResolvedValue(false);
|
|
160
|
-
jest.spyOn(jobExecutionTaskService, `runJobExecutionTask`).mockResolvedValue('mock-task-id');
|
|
161
|
-
|
|
162
|
-
// Mock job manifest and context services
|
|
163
|
-
const mockJobManifest = createMockJobManifest();
|
|
164
|
-
const mockJobContext = createMockJobContext();
|
|
165
|
-
|
|
166
|
-
jest.spyOn(jobManifestService, 'findJobManifest').mockResolvedValue(mockJobManifest);
|
|
167
|
-
jest.spyOn(jobContextService, 'findJobContext').mockResolvedValue(mockJobContext);
|
|
168
|
-
|
|
169
|
-
await jobQueueService.checkAndStartQueuedJob(mockCheckAndStartQueuedJobParams);
|
|
170
|
-
|
|
171
|
-
// Verify that the job execution task was started
|
|
172
|
-
expect(jobExecutionTaskService.runJobExecutionTask).toHaveBeenCalledWith(
|
|
173
|
-
expect.objectContaining({
|
|
174
|
-
jobExecution: mockExecutionOld,
|
|
175
|
-
}),
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
// Verify that the execution status was updated
|
|
179
|
-
expect(mockJobExecutionRepository.update).toHaveBeenCalledWith(
|
|
180
|
-
mockExecutionOld.id,
|
|
181
|
-
{
|
|
182
|
-
ecsTaskId: 'mock-task-id',
|
|
183
|
-
status: JOB_EXECUTION_STATUS.running,
|
|
184
|
-
timeStarted: expect.any(String),
|
|
185
|
-
},
|
|
186
|
-
mockExecutionOld.jobName,
|
|
187
|
-
);
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { JobExecutionTaskService } from '../JobExecutionTaskService/JobExecutionTaskService';
|
|
2
|
-
import { CheckAndStartQueuedJobTaskParams } from './JobQueueService.defs';
|
|
3
|
-
import { JOB_EXECUTION_STATUS } from '../../constants/JobExecutionStatus.constants';
|
|
4
|
-
import { JobExecutionRepository } from '../../repository';
|
|
5
|
-
import { sortByTimeQueued } from '../../utils';
|
|
6
|
-
import { provideSingleton } from '../../singletonProvider';
|
|
7
|
-
import { inject } from 'inversify';
|
|
8
|
-
|
|
9
|
-
@provideSingleton(JobQueueService)
|
|
10
|
-
export class JobQueueService {
|
|
11
|
-
public constructor(
|
|
12
|
-
@inject(JobExecutionTaskService) private readonly jobExecutionTaskService: JobExecutionTaskService,
|
|
13
|
-
@inject(JobExecutionRepository) private readonly jobExecutionRepository: JobExecutionRepository,
|
|
14
|
-
) {}
|
|
15
|
-
|
|
16
|
-
public async checkAndStartQueuedJob(params: CheckAndStartQueuedJobTaskParams): Promise<string | null> {
|
|
17
|
-
const hasReachedMaxConcurrencyForTenant = await this.jobExecutionTaskService.hasReachedMaxTenantConcurrency({
|
|
18
|
-
clusterArn: params.clusterArn,
|
|
19
|
-
runtimeTaskFamily: params.runtimeTaskFamily,
|
|
20
|
-
maxTenantConcurrentTasks: params.maxTenantConcurrentTasks,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
if (!hasReachedMaxConcurrencyForTenant) {
|
|
24
|
-
const executions = await this.jobExecutionRepository.list({
|
|
25
|
-
jobName: params.jobName,
|
|
26
|
-
status: JOB_EXECUTION_STATUS.queued,
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
if (executions.length > 0) {
|
|
30
|
-
const executionToStart = executions.sort(sortByTimeQueued)[0];
|
|
31
|
-
const ecsTaskId = await this.jobExecutionTaskService.runJobExecutionTask({
|
|
32
|
-
jobExecution: executionToStart,
|
|
33
|
-
|
|
34
|
-
awsRegion: params.awsRegion,
|
|
35
|
-
clusterArn: params.clusterArn,
|
|
36
|
-
subnets: params.subnets,
|
|
37
|
-
taskDefinitionArn: params.taskDefinitionArn,
|
|
38
|
-
|
|
39
|
-
tenantId: params.tenantId,
|
|
40
|
-
shortEnvironment: params.shortEnvironment,
|
|
41
|
-
shortRegion: params.shortRegion,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
await this.jobExecutionRepository.update(
|
|
45
|
-
executionToStart.id,
|
|
46
|
-
{
|
|
47
|
-
ecsTaskId,
|
|
48
|
-
status: JOB_EXECUTION_STATUS.running,
|
|
49
|
-
timeStarted: new Date().toISOString(),
|
|
50
|
-
},
|
|
51
|
-
executionToStart.jobName,
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
return executionToStart.id;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
}
|