| 24 | } |
| 25 | |
| 26 | func (r *DatabaseReport) Run(ctx context.Context, opts *DatabaseReportOptions) { |
| 27 | r.Warnings = []health.Message{} |
| 28 | r.Severity = health.SeverityOK |
| 29 | r.Dismissed = opts.Dismissed |
| 30 | |
| 31 | r.ThresholdMS = opts.Threshold.Milliseconds() |
| 32 | if r.ThresholdMS == 0 { |
| 33 | r.ThresholdMS = DatabaseDefaultThreshold.Milliseconds() |
| 34 | } |
| 35 | ctx, cancel := context.WithTimeout(ctx, 5*time.Second) |
| 36 | defer cancel() |
| 37 | |
| 38 | pingCount := 5 |
| 39 | pings := make([]time.Duration, 0, pingCount) |
| 40 | // Ping 5 times and average the latency. |
| 41 | for i := 0; i < pingCount; i++ { |
| 42 | pong, err := opts.DB.Ping(ctx) |
| 43 | if err != nil { |
| 44 | r.Error = health.Errorf(health.CodeDatabasePingFailed, "ping database: %s", err) |
| 45 | r.Severity = health.SeverityError |
| 46 | |
| 47 | return |
| 48 | } |
| 49 | pings = append(pings, pong) |
| 50 | } |
| 51 | slices.Sort(pings) |
| 52 | |
| 53 | // Take the median ping. |
| 54 | latency := pings[pingCount/2] |
| 55 | r.Latency = latency.String() |
| 56 | r.LatencyMS = latency.Milliseconds() |
| 57 | if r.LatencyMS >= r.ThresholdMS { |
| 58 | r.Severity = health.SeverityWarning |
| 59 | r.Warnings = append(r.Warnings, health.Messagef(health.CodeDatabasePingSlow, "median database ping above threshold")) |
| 60 | } |
| 61 | r.Healthy = true |
| 62 | r.Reachable = true |
| 63 | } |