Skip to content

Commit

Permalink
Check invariants hourly (#927)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbryzek authored Jun 6, 2024
1 parent a4a7a48 commit eaa82ea
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 61 deletions.
1 change: 1 addition & 0 deletions api/app/actors/PeriodicActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class PeriodicActor @Inject() (
schedule(CleanupDeletions, FiniteDuration(1, HOURS)),
schedule(ScheduleMigrateVersions, FiniteDuration(12, HOURS)),
schedule(ScheduleSyncGeneratorServices, FiniteDuration(1, HOURS)),
schedule(CheckInvariants, FiniteDuration(1, HOURS)),
)
}

Expand Down
44 changes: 0 additions & 44 deletions api/app/invariants/CheckInvariants.scala

This file was deleted.

54 changes: 54 additions & 0 deletions api/app/processor/CheckInvariantsProcessor.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package processor

import anorm.SqlParser
import cats.data.ValidatedNec
import cats.implicits._
import invariants.{Invariant, Invariants}
import io.apibuilder.task.v0.models._
import lib.{AppConfig, EmailUtil, Person}
import play.api.db.Database

import javax.inject.Inject

case class InvariantResult(invariant: Invariant, count: Long)

class CheckInvariantsProcessor @Inject()(
args: TaskProcessorArgs,
appConfig: AppConfig,
invariants: Invariants,
database: Database,
email: EmailUtil,
) extends TaskProcessor(args, TaskType.CheckInvariants) {

override def processRecord(id: String): ValidatedNec[String, Unit] = {
val results = invariants.all.map { i =>
val count = database.withConnection { c =>
i.query.as(SqlParser.long(1).*)(c).headOption.getOrElse(0L)
}
InvariantResult(i, count)
}
sendResults(results)
().validNec
}

private[this] def sendResults(results: Seq[InvariantResult]): Unit = {
val (noErrors, withErrors) = results.partition(_.count == 0)

println(s"# Invariants checked with no errors: ${noErrors.length}")
if (withErrors.nonEmpty) {
lazy val subject = if (withErrors.length == 1) {
"1 Error"
} else {
s"${withErrors.length} Errors"
}
lazy val body = views.html.emails.invariants(appConfig, noErrors.map(_.invariant.name), withErrors).toString
appConfig.sendErrorsTo.foreach { recipientEmail =>
email.sendHtml(
to = Person(email = recipientEmail),
subject = s"[API Builder Invariants] $subject",
body = body
)
}
}
}
}
4 changes: 3 additions & 1 deletion api/app/processor/TaskActorCompanion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class TaskActorCompanion @Inject() (
userCreated: UserCreatedProcessor,
scheduleSyncGeneratorServices: ScheduleSyncGeneratorServicesProcessor,
syncGeneratorService: SyncGeneratorServiceProcessor,
email: EmailProcessor
email: EmailProcessor,
checkInvariants: CheckInvariantsProcessor,
) {

def process(typ: TaskType): Unit = {
Expand All @@ -23,6 +24,7 @@ class TaskActorCompanion @Inject() (
private[this] def lookup(typ: TaskType): BaseTaskProcessor = {
import TaskType._
typ match {
case CheckInvariants => checkInvariants
case IndexApplication => indexApplication
case CleanupDeletions => cleanupDeletions
case DiffVersion => diffVersion
Expand Down
27 changes: 27 additions & 0 deletions api/app/views/emails/invariants.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@(
appConfig: lib.AppConfig,
noErrors: Seq[String],
withErrors: Seq[processor.InvariantResult]
)

<h2>
The following invariants resulted in a non zero value
</h2>

<ul>
@for(i <- withErrors) {
<li> @{i.invariant.name}: @{i.count}
<blockquote>@{i.invariant.query.interpolate()}</blockquote>
</li>
}
</ul>

<h2>
The following invariants were all valid
</h2>

<ul>
@for(i <- noErrors) {
<li> @i </li>
}
</ul>
13 changes: 0 additions & 13 deletions api/test/invariants/CheckInvariantsSpec.scala

This file was deleted.

13 changes: 13 additions & 0 deletions api/test/processor/CheckInvariantsProcessorSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package processor

import org.scalatestplus.play.PlaySpec
import org.scalatestplus.play.guice.GuiceOneAppPerSuite

class CheckInvariantsProcessorSpec extends PlaySpec with GuiceOneAppPerSuite with db.Helpers {

private def processor: CheckInvariantsProcessor = injector.instanceOf[CheckInvariantsProcessor]

"process" in {
processor.processRecord("periodic")
}
}
7 changes: 4 additions & 3 deletions generated/app/ApicollectiveApibuilderTaskV0Client.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Generated by API Builder - https://www.apibuilder.io
* Service version: 0.16.24
* Service version: 0.16.26
* apibuilder app.apibuilder.io/apicollective/apibuilder-task/latest/play_2_8_client
*/
package io.apibuilder.task.v0.models {
Expand Down Expand Up @@ -60,6 +60,7 @@ package io.apibuilder.task.v0.models {
object TaskType {

case object Email extends TaskType { override def toString = "email" }
case object CheckInvariants extends TaskType { override def toString = "check_invariants" }
case object IndexApplication extends TaskType { override def toString = "index_application" }
case object CleanupDeletions extends TaskType { override def toString = "cleanup_deletions" }
case object ScheduleMigrateVersions extends TaskType { override def toString = "schedule_migrate_versions" }
Expand All @@ -86,7 +87,7 @@ package io.apibuilder.task.v0.models {
* lower case to avoid collisions with the camel cased values
* above.
*/
val all: scala.List[TaskType] = scala.List(Email, IndexApplication, CleanupDeletions, ScheduleMigrateVersions, MigrateVersion, ScheduleSyncGeneratorServices, SyncGeneratorService, DiffVersion, UserCreated)
val all: scala.List[TaskType] = scala.List(Email, CheckInvariants, IndexApplication, CleanupDeletions, ScheduleMigrateVersions, MigrateVersion, ScheduleSyncGeneratorServices, SyncGeneratorService, DiffVersion, UserCreated)

private[this]
val byName: Map[String, TaskType] = all.map(x => x.toString.toLowerCase -> x).toMap
Expand Down Expand Up @@ -466,7 +467,7 @@ package io.apibuilder.task.v0 {

val Namespace = "io.apibuilder.task.v0"
val UserAgent = "apibuilder app.apibuilder.io/apicollective/apibuilder-task/latest/play_2_8_client"
val Version = "0.16.24"
val Version = "0.16.26"
val VersionMajor = 0

}
Expand Down
1 change: 1 addition & 0 deletions spec/apibuilder-task.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"task_type": {
"values": [
{ "name": "email" },
{ "name": "check_invariants" },
{ "name": "index_application" },
{ "name": "cleanup_deletions" },
{ "name": "schedule_migrate_versions" },
Expand Down

0 comments on commit eaa82ea

Please sign in to comment.