-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/** | ||
* AWS SchedulerClient client. | ||
* @class SchedulerClient | ||
* @see {@link https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-eventbridge/index.html|@aws-sdk/client-scheduler} | ||
* @param {Object} parameters | ||
* @param {string} [parameters.name=scheduler] Client name. | ||
* @param {string} [parameters.reqId=<uuid>] Request id. | ||
* @param {Object} [parameters.log=<logger>] Pino compatible logger. | ||
* @param {Constructor} [parameters.AwsSdkSchedulerClient=SchedulerClient] | ||
* Constructor for a SchedulerClient from the AWS SDK. | ||
* @param {Object} [parameters.params={}] | ||
* Additional params to pass to the AwsSdkSchedulerClient constructor. | ||
*/ | ||
|
||
/** | ||
* Get a schedule. | ||
* @async | ||
* @function getSchedule | ||
* @memberof SchedulerClient | ||
* @instance | ||
* @param {Object[]} [name] Name of the schedule to get. | ||
* @param {Object} [params=[]] Additional params to pass to the GetScheduleCommand. | ||
* @return {Promise<Object>} Response normalized to camel case. | ||
*/ | ||
|
||
/** | ||
* Create a schedule. | ||
* @async | ||
* @function createSchedule | ||
* @memberof SchedulerClient | ||
* @instance | ||
* @param {Object[]} [name] Name of the schedule to create. | ||
* @param {Object} [params=[]] Additional params to pass to the CreateScheduleCommand. | ||
* @return {Promise<Object>} Response normalized to camel case. | ||
*/ | ||
|
||
/** | ||
* Delete a schedule. | ||
* @async | ||
* @function deleteSchedule | ||
* @memberof SchedulerClient | ||
* @instance | ||
* @param {Object[]} [name] Name of the schedule to delete. | ||
* @param {Object} [params=[]] Additional params to pass to the DeleteScheduleCommand. | ||
* @return {Promise<Object>} Response normalized to camel case. | ||
*/ | ||
|
||
/** | ||
* Update a schedule. | ||
* AWS uses a replace all attributes strategy when updating schedules. | ||
* This method simplifies updates by getting the existing schedule first and merging all existing top level keys with the new parameter values. | ||
* AWS schedules | ||
* @async | ||
* @function deleteSchedule | ||
* @memberof SchedulerClient | ||
* @instance | ||
* @param {Object[]} [name] Name of the schedule to update. | ||
* @param {Object} [params=[]] Additional params to pass to the UpdateScheduleCommand. | ||
* @return {Promise<Object>} Response normalized to camel case. | ||
*/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { | ||
SchedulerClient as AwsSdkSchedulerClient, | ||
CreateScheduleCommand, | ||
DeleteScheduleCommand, | ||
GetScheduleCommand, | ||
UpdateScheduleCommand | ||
} from '@aws-sdk/client-scheduler' | ||
import { v4 as uuidv4 } from 'uuid' | ||
import { createLogger } from '@meltwater/mlabs-logger' | ||
|
||
import { createCache } from '../cache.js' | ||
import { keysToCamelCase, keysToPascalCase } from '../case.js' | ||
|
||
const createClient = createCache() | ||
|
||
export class SchedulerClient { | ||
#client | ||
#reqId | ||
#log | ||
|
||
constructor({ | ||
name = 'scheduler', | ||
reqId = uuidv4(), | ||
log = createLogger(), | ||
AwsSchedulerClient = AwsSdkSchedulerClient, | ||
params = {} | ||
}) { | ||
this.#client = createClient(name, () => new AwsSchedulerClient(params)) | ||
this.#reqId = reqId | ||
this.#log = log.child({ | ||
params, | ||
client: name, | ||
class: SchedulerClient.name, | ||
reqId | ||
}) | ||
} | ||
|
||
async getSchedule(scheduleName, params = {}) { | ||
const log = this.#log.child({ | ||
scheduleName, | ||
meta: params, | ||
method: SchedulerClient.prototype.getSchedule.name | ||
}) | ||
try { | ||
log.info('start') | ||
const req = formatReq({ ...params, name: scheduleName }) | ||
const command = new GetScheduleCommand(req) | ||
|
||
const res = await this.#client.send(command) | ||
|
||
const data = formatRes(res) | ||
|
||
log.debug({ data }, 'data') | ||
log.info('end') | ||
return data | ||
} catch (err) { | ||
log.error({ err }, 'fail') | ||
throw err | ||
} | ||
} | ||
|
||
async createSchedule(scheduleName, params = {}) { | ||
const log = this.#log.child({ | ||
scheduleName, | ||
meta: params, | ||
method: SchedulerClient.prototype.createSchedule.name | ||
}) | ||
try { | ||
log.info('start') | ||
const req = formatReq({ ...params, name: scheduleName }) | ||
const command = new CreateScheduleCommand(req) | ||
|
||
const res = await this.#client.send(command) | ||
|
||
const data = formatRes(res) | ||
|
||
log.debug({ data }, 'data') | ||
log.info('end') | ||
return data | ||
} catch (err) { | ||
log.error({ err }, 'fail') | ||
throw err | ||
} | ||
} | ||
|
||
async deleteSchedule(scheduleName, params = {}) { | ||
const log = this.#log.child({ | ||
scheduleName, | ||
meta: params, | ||
method: SchedulerClient.prototype.deleteSchedule.name | ||
}) | ||
try { | ||
log.info('start') | ||
const req = formatReq({ name: scheduleName }) | ||
const command = new DeleteScheduleCommand(req) | ||
|
||
const res = await this.#client.send(command) | ||
|
||
const data = formatRes(res) | ||
|
||
log.debug({ data }, 'data') | ||
log.info('end') | ||
return data | ||
} catch (err) { | ||
log.error({ err }, 'fail') | ||
throw err | ||
} | ||
} | ||
|
||
async updateSchedule(scheduleName, params = {}) { | ||
const log = this.#log.child({ | ||
scheduleName, | ||
meta: params, | ||
method: SchedulerClient.prototype.updateSchedule.name | ||
}) | ||
try { | ||
log.info('start') | ||
const schedule = await this.getSchedule(scheduleName) | ||
|
||
const req = formatReq({ ...schedule, ...params, name: scheduleName }) | ||
const command = new UpdateScheduleCommand(req) | ||
|
||
const res = await this.#client.send(command) | ||
|
||
const data = formatRes(res) | ||
|
||
log.debug({ data }, 'data') | ||
log.info('end') | ||
return data | ||
} catch (err) { | ||
log.error({ err }, 'fail') | ||
throw err | ||
} | ||
} | ||
} | ||
|
||
const formatReq = keysToPascalCase | ||
const formatRes = keysToCamelCase |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import test from 'ava' | ||
import * as td from 'testdouble' | ||
import { v4 as uuidv4 } from 'uuid' | ||
import { createLogger } from '@meltwater/mlabs-logger' | ||
import { | ||
CreateScheduleCommand, | ||
Check failure on line 6 in lib/clients/scheduler.spec.js GitHub Actions / lint (14)
Check failure on line 6 in lib/clients/scheduler.spec.js GitHub Actions / lint (16)
Check failure on line 6 in lib/clients/scheduler.spec.js GitHub Actions / fix
Check failure on line 6 in lib/clients/scheduler.spec.js GitHub Actions / lint (14)
|
||
DeleteScheduleCommand, | ||
Check failure on line 7 in lib/clients/scheduler.spec.js GitHub Actions / lint (14)
Check failure on line 7 in lib/clients/scheduler.spec.js GitHub Actions / lint (16)
Check failure on line 7 in lib/clients/scheduler.spec.js GitHub Actions / fix
Check failure on line 7 in lib/clients/scheduler.spec.js GitHub Actions / lint (14)
|
||
GetScheduleCommand, | ||
UpdateScheduleCommand | ||
Check failure on line 9 in lib/clients/scheduler.spec.js GitHub Actions / lint (14)
Check failure on line 9 in lib/clients/scheduler.spec.js GitHub Actions / lint (16)
Check failure on line 9 in lib/clients/scheduler.spec.js GitHub Actions / fix
Check failure on line 9 in lib/clients/scheduler.spec.js GitHub Actions / lint (14)
|
||
} from '@aws-sdk/client-scheduler' | ||
|
||
import { registerTestdoubleMatchers } from '../../testdouble-matchers.js' | ||
|
||
import { SchedulerClient } from './scheduler.js' | ||
|
||
test.before(() => { | ||
registerTestdoubleMatchers(td) | ||
}) | ||
|
||
test.beforeEach((t) => { | ||
t.context.AwsSchedulerClient = td.constructor(['send']) | ||
|
||
t.context.createClient = (t, options) => { | ||
const client = new SchedulerClient({ | ||
name: uuidv4(), | ||
AwsSchedulerClient: t.context.AwsSchedulerClient, | ||
reqId, | ||
log: createLogger({ t }), | ||
...options | ||
}) | ||
|
||
return client | ||
} | ||
}) | ||
|
||
test('constructor: passes params to AWS SchedulerClient', (t) => { | ||
const { AwsSchedulerClient } = t.context | ||
const params = { foo: 'bar' } | ||
const client = new SchedulerClient({ | ||
name: uuidv4(), | ||
AwsSchedulerClient, | ||
params, | ||
log: createLogger({ t }) | ||
}) | ||
td.verify(new AwsSchedulerClient(params)) | ||
t.truthy(client) | ||
}) | ||
|
||
test('getSchedule: returns response', async (t) => { | ||
const { AwsSchedulerClient, createClient } = t.context | ||
const client = createClient(t) | ||
|
||
td.when( | ||
AwsSchedulerClient.prototype.send( | ||
td.matchers.isAwsSdkCommand( | ||
new GetScheduleCommand({ Name: scheduleName }) | ||
) | ||
) | ||
).thenResolve(getScheduleResponse) | ||
|
||
const data = await client.getSchedule(scheduleName) | ||
|
||
t.deepEqual(data, getScheduleResponseFormatted) | ||
}) | ||
|
||
const reqId = 'mock-req-id' | ||
|
||
const scheduleName = 'mock-schedule-name' | ||
|
||
const getScheduleResponse = { ScheduleArn: 'mock-schedule-arn' } | ||
|
||
const getScheduleResponseFormatted = { scheduleArn: 'mock-schedule-arn' } |