@@ -48,7 +48,9 @@ enum Alerting {
48
48
Current . logger ( ) . info ( " Validation time interval: \( timePeriod. hours) h, limit: \( limit) " )
49
49
50
50
let builds = try await Alerting . fetchBuilds ( on: context. application. db, timePeriod: timePeriod, limit: limit)
51
- try await Alerting . runChecks ( for: builds)
51
+ try await Alerting . runBuildChecks ( for: builds)
52
+ try await Alerting . runMonitoring001Check ( on: context. application. db, timePeriod: timePeriod)
53
+ . log ( check: " CHECK_MON_001 " )
52
54
}
53
55
}
54
56
}
@@ -84,7 +86,7 @@ extension Alerting {
84
86
}
85
87
}
86
88
87
- static func runChecks ( for builds: [ BuildInfo ] ) async throws {
89
+ static func runBuildChecks ( for builds: [ BuildInfo ] ) async throws {
88
90
// to do
89
91
// - [ ] doc gen is configured but it failed
90
92
@@ -128,6 +130,49 @@ extension Alerting {
128
130
. map ( BuildInfo . init)
129
131
return builds
130
132
}
133
+
134
+ struct Mon001Row : Decodable , CustomStringConvertible {
135
+ var owner : String
136
+ var repository : String
137
+ var status : Package . Status ?
138
+ var processingStage : Package . ProcessingStage ?
139
+ var updatedAt : Date
140
+
141
+ enum CodingKeys : String , CodingKey {
142
+ case owner
143
+ case repository
144
+ case status
145
+ case processingStage = " processing_stage "
146
+ case updatedAt = " updated_at "
147
+ }
148
+
149
+ var description : String {
150
+ " \( owner) / \( repository) \( status. map { $0. rawValue } ?? " - " ) \( processingStage. map { $0. rawValue } ?? " - " ) \( updatedAt) "
151
+ }
152
+ }
153
+
154
+ static func runMonitoring001Check( on database: Database , timePeriod: TimeAmount ) async throws -> Alerting . Validation {
155
+ guard let db = database as? SQLDatabase else {
156
+ fatalError ( " Database must be an SQLDatabase ('as? SQLDatabase' must succeed) " )
157
+ }
158
+ let rows = try await db. raw ( """
159
+ SELECT
160
+ r.owner,
161
+ r.name AS " repository " ,
162
+ p.status,
163
+ p.processing_stage,
164
+ r.updated_at
165
+ FROM
166
+ repositories r
167
+ JOIN packages p ON r.package_id = p.id
168
+ WHERE
169
+ r.updated_at < now() - INTERVAL \( literal: " \( timePeriod. hours) hours " )
170
+ ORDER BY
171
+ updated_at
172
+ """ )
173
+ . all ( decoding: Mon001Row . self)
174
+ return rows. isValid ( )
175
+ }
131
176
}
132
177
133
178
@@ -222,6 +267,17 @@ extension [Alerting.BuildInfo] {
222
267
}
223
268
224
269
270
+ extension [ Alerting . Mon001Row ] {
271
+ func isValid( ) -> Alerting . Validation {
272
+ if isEmpty {
273
+ return . ok
274
+ } else {
275
+ return . failed( reasons: sorted ( by: { $0. updatedAt < $1. updatedAt } ) . map { " Outdated package: \( $0) " } )
276
+ }
277
+ }
278
+ }
279
+
280
+
225
281
private extension TimeAmount {
226
282
var timeInterval : TimeInterval {
227
283
Double ( nanoseconds) * 1e-9
0 commit comments