@squiz/job-runner-lib 2.7.0 → 2.8.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/job/constants/RetryConfig.constants.d.ts +6 -1
- package/lib/domains/job/constants/RuntimeImage.constants.d.ts +5 -0
- package/lib/domains/job/errors/RuntimeImageTaskDefinitionError.d.ts +7 -0
- package/lib/domains/job/errors/index.d.ts +1 -0
- package/lib/domains/job/manifest/JobManifestTypes.d.ts +13 -1
- package/lib/domains/job/model/Job/Job.d.ts +12 -0
- package/lib/domains/job/repository/JobManifestRepository/JobManifestRepository.d.ts +1 -1
- package/lib/domains/job/repository/JobRepository/JobRepository.d.ts +2 -2
- package/lib/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.d.ts +1 -0
- package/lib/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.defs.d.ts +1 -0
- package/lib/domains/job/utils/ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.d.ts +6 -0
- package/lib/domains/job/utils/ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.types.d.ts +9 -0
- package/lib/domains/job/utils/index.d.ts +2 -0
- package/lib/domains/manifest/index.d.ts +3 -2
- package/lib/domains/manifest/utils/defaultAutoRetry.d.ts +5 -0
- package/lib/domains/manifest/utils/defaultAutoRetry.spec.d.ts +5 -0
- package/lib/index.js +9 -9
- package/lib/index.js.map +4 -4
- package/package.json +2 -2
- package/src/domains/job/constants/RetryConfig.constants.ts +8 -2
- package/src/domains/job/constants/RuntimeImage.constants.ts +7 -1
- package/src/domains/job/errors/RuntimeImageTaskDefinitionError.ts +10 -0
- package/src/domains/job/errors/index.ts +1 -0
- package/src/domains/job/manifest/JobManifestTypes.ts +16 -1
- package/src/domains/job/manifest/mocks/JobManifest.mock.ts +1 -0
- package/src/domains/job/manifest/mocks/JobManifestDto.mock.ts +3 -0
- package/src/domains/job/manifest/mocks/JobManifestRecord.mock.ts +1 -0
- package/src/domains/job/manifest/mocks/JobManifestRequest.mock.ts +1 -0
- package/src/domains/job/model/Job/Job.ts +14 -0
- package/src/domains/job/model/Job/mocks/Job.mock.ts +2 -0
- package/src/domains/job/model/Job/mocks/JobDto.mock.ts +4 -0
- package/src/domains/job/model/Job/mocks/JobRecord.mock.ts +2 -0
- package/src/domains/job/model/Job/mocks/JobRequest.mock.ts +2 -0
- package/src/domains/job/repository/JobManifestRepository/JobManifestRepository.spec.ts +56 -4
- package/src/domains/job/repository/JobManifestRepository/JobManifestRepository.ts +14 -4
- package/src/domains/job/repository/JobRepository/JobRepository.spec.ts +36 -4
- package/src/domains/job/repository/JobRepository/JobRepository.ts +10 -5
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.defs.ts +1 -0
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.spec.ts +53 -3
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.ts +19 -8
- package/src/domains/job/services/JobManifestService/JobManifestService.spec.ts +9 -8
- package/src/domains/job/utils/ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.ts +39 -0
- package/src/domains/job/utils/ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.types.ts +10 -0
- package/src/domains/job/utils/index.ts +2 -0
- package/src/domains/manifest/index.ts +3 -2
- package/src/domains/manifest/utils/defaultAutoRetry.spec.ts +16 -0
- package/src/domains/manifest/utils/defaultAutoRetry.ts +6 -0
- package/src/domains/manifest/utils/validateRuntimeImage.spec.ts +11 -4
|
@@ -7,9 +7,10 @@ import { ConflictException, ECSClient, RunTaskCommand } from '@aws-sdk/client-ec
|
|
|
7
7
|
import { createHash } from 'node:crypto';
|
|
8
8
|
import { JobDetailsRepository, JobUploadsRepository } from '../../S3Repository';
|
|
9
9
|
import { JOB_EXECUTION_STATUS } from '../../constants/JobExecutionStatus.constants';
|
|
10
|
+
import { JobManifest } from '../../manifest';
|
|
10
11
|
import { JobExecution } from '../../model/JobExecution';
|
|
11
12
|
import { JobExecutionRepository } from '../../repository';
|
|
12
|
-
import { getAwsTags } from '../../utils';
|
|
13
|
+
import { getAwsTags, resolveRuntimeImageTaskDefinitionArn } from '../../utils';
|
|
13
14
|
import { JobContextService } from '../JobContextService/JobContextService';
|
|
14
15
|
import { JobManifestService } from '../JobManifestService/JobManifestService';
|
|
15
16
|
import { HasReachedMaxTenantConcurrencyParams, RunJobTaskParams } from './JobExecutionTaskService.defs';
|
|
@@ -56,7 +57,13 @@ export class JobExecutionTaskService {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
public async runJobExecutionTask(params: RunJobTaskParams): Promise<string | undefined> {
|
|
59
|
-
const
|
|
60
|
+
const jobManifest = await this.findJobManifest(params.jobExecution);
|
|
61
|
+
const taskDefinitionArn = resolveRuntimeImageTaskDefinitionArn({
|
|
62
|
+
image: jobManifest?.image,
|
|
63
|
+
taskDefinitionArnsByRuntimeImage: params.taskDefinitionArnsByRuntimeImage,
|
|
64
|
+
legacyTaskDefinitionArn: params.taskDefinitionArn,
|
|
65
|
+
});
|
|
66
|
+
const jobDetailsFileUrl = await this.createJobDetailsFile(params.tenantId, params.jobExecution, jobManifest);
|
|
60
67
|
const tags = getAwsTags({
|
|
61
68
|
tenant: params.tenantId,
|
|
62
69
|
region: params.awsRegion,
|
|
@@ -104,7 +111,7 @@ export class JobExecutionTaskService {
|
|
|
104
111
|
const result = await this.ecsClient.send(
|
|
105
112
|
new RunTaskCommand({
|
|
106
113
|
cluster: params.clusterArn,
|
|
107
|
-
taskDefinition:
|
|
114
|
+
taskDefinition: taskDefinitionArn,
|
|
108
115
|
overrides: {
|
|
109
116
|
containerOverrides: [
|
|
110
117
|
{
|
|
@@ -183,11 +190,11 @@ export class JobExecutionTaskService {
|
|
|
183
190
|
return createHash('sha1').update(key).digest('hex');
|
|
184
191
|
}
|
|
185
192
|
|
|
186
|
-
private async createJobDetailsFile(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
193
|
+
private async createJobDetailsFile(
|
|
194
|
+
tenantId: string,
|
|
195
|
+
executionToStart: JobExecution,
|
|
196
|
+
jobManifest: JobManifest | null,
|
|
197
|
+
): Promise<string> {
|
|
191
198
|
const jobContext = await this.jobContextService.findJobContext(executionToStart.context);
|
|
192
199
|
|
|
193
200
|
const jobDetailsFileName = await this.jobDetailsRepository.createJobDetailsFile(
|
|
@@ -198,4 +205,8 @@ export class JobExecutionTaskService {
|
|
|
198
205
|
);
|
|
199
206
|
return await this.jobDetailsRepository.getS3SignedUrl(jobDetailsFileName);
|
|
200
207
|
}
|
|
208
|
+
|
|
209
|
+
private async findJobManifest(executionToStart: JobExecution): Promise<JobManifest | null> {
|
|
210
|
+
return await this.jobManifestService.findJobManifest(executionToStart.jobName, executionToStart.version);
|
|
211
|
+
}
|
|
201
212
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* @license
|
|
3
3
|
* Copyright Squiz Australia Pty Ltd. All Rights Reserved.
|
|
4
4
|
*/
|
|
5
|
-
import { initIocContainer, iocContainer } from '../../../../mocks/mockIoc';
|
|
6
5
|
import {
|
|
7
6
|
DynamoDBClient,
|
|
8
7
|
DynamoDBClientConfig,
|
|
@@ -10,7 +9,13 @@ import {
|
|
|
10
9
|
PutItemCommandOutput,
|
|
11
10
|
ScanCommandOutput,
|
|
12
11
|
} from '@aws-sdk/client-dynamodb';
|
|
13
|
-
import {
|
|
12
|
+
import { initIocContainer, iocContainer } from '../../../../mocks/mockIoc';
|
|
13
|
+
import { ENTITY_TYPES } from '../../constants/Repository.constants';
|
|
14
|
+
import {
|
|
15
|
+
createMockClientGetResponse,
|
|
16
|
+
createMockClientPutResponse,
|
|
17
|
+
createMockClientScanResponse,
|
|
18
|
+
} from '../../core/dynamoClient.mock';
|
|
14
19
|
import {
|
|
15
20
|
createMockCreateJobManifestRequest,
|
|
16
21
|
createMockJobManifest,
|
|
@@ -19,12 +24,7 @@ import {
|
|
|
19
24
|
createMockJobManifestRecord,
|
|
20
25
|
JobManifest,
|
|
21
26
|
} from '../../manifest';
|
|
22
|
-
import {
|
|
23
|
-
createMockClientGetResponse,
|
|
24
|
-
createMockClientPutResponse,
|
|
25
|
-
createMockClientScanResponse,
|
|
26
|
-
} from '../../core/dynamoClient.mock';
|
|
27
|
-
import { ENTITY_TYPES } from '../../constants/Repository.constants';
|
|
27
|
+
import { JobManifestService } from './JobManifestService';
|
|
28
28
|
|
|
29
29
|
initIocContainer();
|
|
30
30
|
|
|
@@ -88,6 +88,7 @@ describe('JobManifestService', (): void => {
|
|
|
88
88
|
version: mockJobManifestItem.version.S as string,
|
|
89
89
|
timeoutSeconds: parseInt(mockJobManifestItem.timeoutSeconds.N as string),
|
|
90
90
|
image: mockJobManifestItem.image.S as string,
|
|
91
|
+
autoRetry: false,
|
|
91
92
|
type: `manifest`,
|
|
92
93
|
} as JobManifest);
|
|
93
94
|
expect(mockSend).toBeCalledTimes(1);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Squiz Australia Pty Ltd. All Rights Reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
LEGACY_RUNTIME_IMAGE,
|
|
8
|
+
SUPPORTED_RUNTIME_IMAGES,
|
|
9
|
+
getRuntimeImageOrDefault,
|
|
10
|
+
isSupportedRuntimeImage,
|
|
11
|
+
} from '../../constants/RuntimeImage.constants';
|
|
12
|
+
import { RuntimeImageTaskDefinitionError } from '../../errors';
|
|
13
|
+
import { ResolveRuntimeImageTaskDefinitionArnParams } from './ResolveRuntimeImageTaskDefinitionArn.types';
|
|
14
|
+
|
|
15
|
+
export const resolveRuntimeImageTaskDefinitionArn = ({
|
|
16
|
+
image,
|
|
17
|
+
taskDefinitionArnsByRuntimeImage,
|
|
18
|
+
legacyTaskDefinitionArn,
|
|
19
|
+
}: ResolveRuntimeImageTaskDefinitionArnParams): string => {
|
|
20
|
+
const runtimeImage = getRuntimeImageOrDefault(image);
|
|
21
|
+
|
|
22
|
+
if (!isSupportedRuntimeImage(runtimeImage)) {
|
|
23
|
+
throw new RuntimeImageTaskDefinitionError(
|
|
24
|
+
`Unsupported runtime image "${runtimeImage}". Supported images are: ${SUPPORTED_RUNTIME_IMAGES.join(', ')}`,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const taskDefinitionArn =
|
|
29
|
+
taskDefinitionArnsByRuntimeImage[runtimeImage] ||
|
|
30
|
+
(runtimeImage === LEGACY_RUNTIME_IMAGE ? legacyTaskDefinitionArn : undefined);
|
|
31
|
+
|
|
32
|
+
if (!taskDefinitionArn) {
|
|
33
|
+
throw new RuntimeImageTaskDefinitionError(
|
|
34
|
+
`No ECS task definition ARN configured for runtime image "${runtimeImage}"`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return taskDefinitionArn;
|
|
39
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Squiz Australia Pty Ltd. All Rights Reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ResolveRuntimeImageTaskDefinitionArnParams {
|
|
7
|
+
image: string | null | undefined;
|
|
8
|
+
taskDefinitionArnsByRuntimeImage: Record<string, string>;
|
|
9
|
+
legacyTaskDefinitionArn: string;
|
|
10
|
+
}
|
|
@@ -3,3 +3,5 @@ export * from './GetAwsTags/GetAwsTags.types';
|
|
|
3
3
|
export * from './SlackClient/SlackClient';
|
|
4
4
|
export * from './SlackClient/types/SlackClient.types';
|
|
5
5
|
export * from './SortByTimeQueued/SortByTimeQueued';
|
|
6
|
+
export * from './ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn';
|
|
7
|
+
export * from './ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.types';
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
export * from './services/ManifestServiceForDev';
|
|
2
1
|
export * from './services/JobFunctionService';
|
|
2
|
+
export * from './services/ManifestServiceForDev';
|
|
3
3
|
|
|
4
|
+
export * from './utils/defaultAutoRetry';
|
|
4
5
|
export * from './utils/getAndAssertJobManifestVersion';
|
|
5
6
|
export * from './utils/isValidManifestVersion';
|
|
6
7
|
export * from './utils/validateRuntimeImage';
|
|
7
8
|
|
|
8
|
-
export * from './ManifestModel';
|
|
9
9
|
export * from '../job/manifest/JobManifestV1';
|
|
10
10
|
export * from './errors/ManifestValidationError';
|
|
11
|
+
export * from './ManifestModel';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Squiz Australia Pty Ltd. All Rights Reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defaultAutoRetry } from './defaultAutoRetry';
|
|
7
|
+
|
|
8
|
+
describe('defaultAutoRetry', () => {
|
|
9
|
+
it('returns true when autoRetry is true', () => {
|
|
10
|
+
expect(defaultAutoRetry(true)).toEqual(true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it.each([false, null, undefined])('returns false when autoRetry is %s', (autoRetry) => {
|
|
14
|
+
expect(defaultAutoRetry(autoRetry)).toEqual(false);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import * as runtimeImageConstants from '../../job/constants/RuntimeImage.constants';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
DEPRECATED_RUNTIME_IMAGES,
|
|
9
|
+
RECOMMENDED_RUNTIME_IMAGE,
|
|
10
|
+
SUPPORTED_RUNTIME_IMAGES,
|
|
11
|
+
} from '../../job/constants/RuntimeImage.constants';
|
|
8
12
|
import { ManifestValidationError } from '../errors/ManifestValidationError';
|
|
9
13
|
import { validateAndDefaultRuntimeImage } from './validateRuntimeImage';
|
|
10
14
|
|
|
@@ -21,9 +25,12 @@ describe('validateAndDefaultRuntimeImage', () => {
|
|
|
21
25
|
expect(validateAndDefaultRuntimeImage(null)).toEqual(RECOMMENDED_RUNTIME_IMAGE);
|
|
22
26
|
});
|
|
23
27
|
|
|
24
|
-
it.each(SUPPORTED_RUNTIME_IMAGES
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
it.each(SUPPORTED_RUNTIME_IMAGES.filter((image) => !DEPRECATED_RUNTIME_IMAGES.includes(image)))(
|
|
29
|
+
'returns "%s" when it is supported and not deprecated',
|
|
30
|
+
(supportedImage) => {
|
|
31
|
+
expect(validateAndDefaultRuntimeImage(supportedImage)).toEqual(supportedImage);
|
|
32
|
+
},
|
|
33
|
+
);
|
|
27
34
|
|
|
28
35
|
it('throws ManifestValidationError when the image is not supported', () => {
|
|
29
36
|
expect(() => validateAndDefaultRuntimeImage('node:18')).toThrow(ManifestValidationError);
|