diff --git a/lib/constructs/backup-verification.ts b/lib/constructs/backup-verification.ts index a94e347..b9e9935 100644 --- a/lib/constructs/backup-verification.ts +++ b/lib/constructs/backup-verification.ts @@ -99,16 +99,38 @@ export class BackupVerification extends Construct { ], }); + // Errors alarm: only fires when the function actually runs and errors. + // The function runs once daily, so for ~23h there is no data. Treating + // missing data as BREACHING flipped this alarm OK->ALARM every day around + // 11:01 UTC even though no error ever occurred. NOT_BREACHING means "no + // data = no errors = healthy"; the separate not-running alarm below covers + // the "verification never ran" case. new cloudwatch.Alarm(this, "ErrorAlarm", { alarmName: "forgejo-backup-verification-errors", alarmDescription: "Backup verification Lambda is failing — Slack notifications may not be firing", metric: fn.metricErrors({ period: cdk.Duration.hours(1) }), threshold: 1, evaluationPeriods: 1, - treatMissingData: cloudwatch.TreatMissingData.BREACHING, + treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING, comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, }); + // Not-running alarm: fires if the daily verification did not invoke at all + // in a 24h window. This is the real "missing run" guard that the errors + // alarm's BREACHING setting was previously (and incorrectly) providing. + new cloudwatch.Alarm(this, "NotRunningAlarm", { + alarmName: "forgejo-backup-verification-not-running", + alarmDescription: "Backup verification Lambda has not run in the last 24h — daily verification may be broken", + metric: fn.metricInvocations({ + period: cdk.Duration.hours(24), + statistic: cloudwatch.Stats.SUM, + }), + threshold: 1, + evaluationPeriods: 1, + treatMissingData: cloudwatch.TreatMissingData.BREACHING, + comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, + }); + this.functionArn = fn.functionArn; } }