in src/package-sources/npmjs.ts [347:431]
private registerAlarms(scope: Construct, follower: NpmJsFollower, stager: StageAndNotify, monitoring: IMonitoring, schedule: Rule) {
const failureAlarm = follower.metricErrors().createAlarm(scope, 'NpmJs/Follower/Failures', {
alarmName: `${scope.node.path}/NpmJs/Follower/Failures`,
alarmDescription: [
'The NpmJs follower function failed!',
'',
`RunBook: ${RUNBOOK_URL}`,
'',
`Direct link to Lambda function: ${lambdaFunctionUrl(follower)}`,
].join('\n'),
comparisonOperator: ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
evaluationPeriods: 3,
threshold: 1,
treatMissingData: TreatMissingData.MISSING,
});
monitoring.addHighSeverityAlarm('NpmJs/Follower Failures', failureAlarm);
const notRunningAlarm = follower.metricInvocations({ period: FOLLOWER_RUN_RATE })
.createAlarm(scope, 'NpmJs/Follower/NotRunning', {
alarmName: `${scope.node.path}/NpmJs/Follower/NotRunning`,
alarmDescription: [
'The NpmJs follower function is not running!',
'',
`RunBook: ${RUNBOOK_URL}`,
'',
`Direct link to Lambda function: ${lambdaFunctionUrl(follower)}`,
].join('\n'),
comparisonOperator: ComparisonOperator.LESS_THAN_THRESHOLD,
evaluationPeriods: 2,
threshold: 1,
treatMissingData: TreatMissingData.BREACHING,
});
monitoring.addHighSeverityAlarm('NpmJs/Follower Not Running', notRunningAlarm);
// The period for this alarm needs to match the scheduling interval of the
// follower, otherwise the metric will be too sparse to properly detect
// problems.
const noChangeAlarm = this.metricChangeCount({ period: FOLLOWER_RUN_RATE })
.createAlarm(scope, 'NpmJs/Follower/NoChanges', {
alarmName: `${scope.node.path}/NpmJs/Follower/NoChanges`,
alarmDescription: [
'The NpmJs follower function is no discovering any changes from CouchDB!',
'',
`RunBook: ${RUNBOOK_URL}`,
'',
`Direct link to Lambda function: ${lambdaFunctionUrl(follower)}`,
].join('\n'),
comparisonOperator: ComparisonOperator.LESS_THAN_THRESHOLD,
evaluationPeriods: 2,
threshold: 1,
// If the metric is not emitted, it can be assumed to be zero.
treatMissingData: TreatMissingData.BREACHING,
});
monitoring.addLowSeverityAlarm('Np npmjs.com changes discovered', noChangeAlarm);
const dlqNotEmptyAlarm = new MathExpression({
expression: 'mVisible + mHidden',
usingMetrics: {
mVisible: stager.deadLetterQueue!.metricApproximateNumberOfMessagesVisible({ period: Duration.minutes(1) }),
mHidden: stager.deadLetterQueue!.metricApproximateNumberOfMessagesNotVisible({ period: Duration.minutes(1) }),
},
}).createAlarm(scope, `${scope.node.path}/NpmJs/Stager/DLQNotEmpty`, {
alarmName: `${scope.node.path}/NpmJs/Stager/DLQNotEmpty`,
alarmDescription: [
'The NpmJS package stager is failing - its dead letter queue is not empty',
'',
`Link to the lambda function: ${lambdaFunctionUrl(stager)}`,
`Link to the dead letter queue: ${sqsQueueUrl(stager.deadLetterQueue!)}`,
'',
`Runbook: ${RUNBOOK_URL}`,
].join('/n'),
comparisonOperator: ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
evaluationPeriods: 1,
threshold: 1,
treatMissingData: TreatMissingData.NOT_BREACHING,
});
monitoring.addLowSeverityAlarm('NpmJs/Stager DLQ Not Empty', dlqNotEmptyAlarm);
// Finally - the "not running" alarm depends on the schedule (it won't run until the schedule
// exists!), and the schedule depends on the failure alarm existing (we don't want it to run
// before we can know it is failing). This means the returned `IDependable` effectively ensures
// all alarms have been provisionned already! Isn't it nice!
notRunningAlarm.node.addDependency(schedule);
schedule.node.addDependency(failureAlarm);
}