@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.
Files changed (49) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/lib/domains/job/constants/RetryConfig.constants.d.ts +6 -1
  3. package/lib/domains/job/constants/RuntimeImage.constants.d.ts +5 -0
  4. package/lib/domains/job/errors/RuntimeImageTaskDefinitionError.d.ts +7 -0
  5. package/lib/domains/job/errors/index.d.ts +1 -0
  6. package/lib/domains/job/manifest/JobManifestTypes.d.ts +13 -1
  7. package/lib/domains/job/model/Job/Job.d.ts +12 -0
  8. package/lib/domains/job/repository/JobManifestRepository/JobManifestRepository.d.ts +1 -1
  9. package/lib/domains/job/repository/JobRepository/JobRepository.d.ts +2 -2
  10. package/lib/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.d.ts +1 -0
  11. package/lib/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.defs.d.ts +1 -0
  12. package/lib/domains/job/utils/ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.d.ts +6 -0
  13. package/lib/domains/job/utils/ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.types.d.ts +9 -0
  14. package/lib/domains/job/utils/index.d.ts +2 -0
  15. package/lib/domains/manifest/index.d.ts +3 -2
  16. package/lib/domains/manifest/utils/defaultAutoRetry.d.ts +5 -0
  17. package/lib/domains/manifest/utils/defaultAutoRetry.spec.d.ts +5 -0
  18. package/lib/index.js +9 -9
  19. package/lib/index.js.map +4 -4
  20. package/package.json +2 -2
  21. package/src/domains/job/constants/RetryConfig.constants.ts +8 -2
  22. package/src/domains/job/constants/RuntimeImage.constants.ts +7 -1
  23. package/src/domains/job/errors/RuntimeImageTaskDefinitionError.ts +10 -0
  24. package/src/domains/job/errors/index.ts +1 -0
  25. package/src/domains/job/manifest/JobManifestTypes.ts +16 -1
  26. package/src/domains/job/manifest/mocks/JobManifest.mock.ts +1 -0
  27. package/src/domains/job/manifest/mocks/JobManifestDto.mock.ts +3 -0
  28. package/src/domains/job/manifest/mocks/JobManifestRecord.mock.ts +1 -0
  29. package/src/domains/job/manifest/mocks/JobManifestRequest.mock.ts +1 -0
  30. package/src/domains/job/model/Job/Job.ts +14 -0
  31. package/src/domains/job/model/Job/mocks/Job.mock.ts +2 -0
  32. package/src/domains/job/model/Job/mocks/JobDto.mock.ts +4 -0
  33. package/src/domains/job/model/Job/mocks/JobRecord.mock.ts +2 -0
  34. package/src/domains/job/model/Job/mocks/JobRequest.mock.ts +2 -0
  35. package/src/domains/job/repository/JobManifestRepository/JobManifestRepository.spec.ts +56 -4
  36. package/src/domains/job/repository/JobManifestRepository/JobManifestRepository.ts +14 -4
  37. package/src/domains/job/repository/JobRepository/JobRepository.spec.ts +36 -4
  38. package/src/domains/job/repository/JobRepository/JobRepository.ts +10 -5
  39. package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.defs.ts +1 -0
  40. package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.spec.ts +53 -3
  41. package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.ts +19 -8
  42. package/src/domains/job/services/JobManifestService/JobManifestService.spec.ts +9 -8
  43. package/src/domains/job/utils/ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.ts +39 -0
  44. package/src/domains/job/utils/ResolveRuntimeImageTaskDefinitionArn/ResolveRuntimeImageTaskDefinitionArn.types.ts +10 -0
  45. package/src/domains/job/utils/index.ts +2 -0
  46. package/src/domains/manifest/index.ts +3 -2
  47. package/src/domains/manifest/utils/defaultAutoRetry.spec.ts +16 -0
  48. package/src/domains/manifest/utils/defaultAutoRetry.ts +6 -0
  49. 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 jobDetailsFileUrl = await this.createJobDetailsFile(params.tenantId, params.jobExecution);
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: params.taskDefinitionArn,
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(tenantId: string, executionToStart: JobExecution): Promise<string> {
187
- const jobManifest = await this.jobManifestService.findJobManifest(
188
- executionToStart.jobName,
189
- executionToStart.version,
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 { JobManifestService } from './JobManifestService';
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
+ });
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * @license
3
+ * Copyright Squiz Australia Pty Ltd. All Rights Reserved.
4
+ */
5
+
6
+ export const defaultAutoRetry = (autoRetry: boolean | null | undefined): boolean => autoRetry === true;
@@ -4,7 +4,11 @@
4
4
  */
5
5
 
6
6
  import * as runtimeImageConstants from '../../job/constants/RuntimeImage.constants';
7
- import { RECOMMENDED_RUNTIME_IMAGE, SUPPORTED_RUNTIME_IMAGES } from '../../job/constants/RuntimeImage.constants';
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)('returns "%s" when it is in the supported list', (supportedImage) => {
25
- expect(validateAndDefaultRuntimeImage(supportedImage)).toEqual(supportedImage);
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);