ADR 0227 rule 8 / ADR 0240 rule 2 refuse a module with no health check of another kind beside a tool check. mesh-mail-notifier has one process (notify); wiring mail_notifier_health as its manifest health, as the review note's wording suggested (mirroring mesh-mail's watch/mail_health), trips that rule because mesh-mail also has keep (kind unit) beside watch. mail_notifier_health stays built, tested and callable; notify's manifest health stays kind unit until the lead decides how a one-process module gets this automatically.
63 lines
2.9 KiB
Go
63 lines
2.9 KiB
Go
package main
|
|
|
|
// mesh-mail-notifier's own health (review round 1 of issue 800, which added this tool beside mail-notifier's
|
|
// seat verb status, as mesh-mail's own health tool is mail_health beside its seat tools). A notice that fails
|
|
// to send stays pending and is retried, at most once a minute (Flush, notifier.go); the account's
|
|
// failing-since stays in the Store, so this tool — its own process, asked separately by the node-engine or by
|
|
// mesh_call — sees the same account the live notifier does, with no state of its own to lose between asks.
|
|
//
|
|
// Unhealthy once an account's notice has failed to show for more than UnhealthyAfter; healthy otherwise, even
|
|
// while a notice is mid-retry.
|
|
//
|
|
// STOP (review round 1 of issue 800, not decided by its note): this tool is served and tested, but module.json
|
|
// does not name it as the notify process's own health check — mesh-mail-notifier has one process (notify), and
|
|
// the catalogue's gate refuses a module judged only by its own tool, with no check of another kind beside it
|
|
// (ADR 0227 rule 8, ADR 0240 rule 2; internal/catalogue/health.go ~297 in mesh-controller). mesh-mail avoids
|
|
// this because it has two processes — keep (kind unit) beside watch (kind tool, mail_health); mesh-mail-notifier
|
|
// has only notify, so wiring this tool the same way trips the gate. notify's health stays kind unit (liveness,
|
|
// as it was before this round) until the lead decides how a one-process module gets an automatic, node-engine
|
|
// enforced health of this kind: a second process judged some other way, or a change to the gate's rule.
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/health"
|
|
)
|
|
|
|
// HealthTool is the module's own health tool the node-engine asks (beside mail-notifier.status, the seat's own verb).
|
|
const HealthTool = "mail_notifier_health"
|
|
|
|
// UnhealthyAfter is how long a notice may fail to send before that is unhealthy, not merely retrying.
|
|
const UnhealthyAfter = 10 * time.Minute
|
|
|
|
// Judge is mesh-mail-notifier's health, from the failures the Store keeps.
|
|
func Judge(failures map[string]FailureStatus, now time.Time) health.Answer {
|
|
if len(failures) == 0 {
|
|
return health.Healthy("every notice shown; none pending a retry")
|
|
}
|
|
accounts := make([]string, 0, len(failures))
|
|
for account := range failures {
|
|
accounts = append(accounts, account)
|
|
}
|
|
sort.Strings(accounts)
|
|
|
|
var problems, retrying []string
|
|
for _, account := range accounts {
|
|
f := failures[account]
|
|
age := now.Sub(f.Since).Round(time.Second)
|
|
if now.Sub(f.Since) > UnhealthyAfter {
|
|
problems = append(problems, fmt.Sprintf("%s: its notice has failed to show for %s (%d attempt(s), last: %s)",
|
|
account, age, f.Count, f.LastError))
|
|
} else {
|
|
retrying = append(retrying, fmt.Sprintf("%s has been retrying for %s", account, age))
|
|
}
|
|
}
|
|
if len(problems) > 0 {
|
|
return health.Unhealthy(strings.Join(problems, "; "))
|
|
}
|
|
return health.Healthy(strings.Join(retrying, "; "))
|
|
}
|