Page MenuHomePhabricator

[infra,o11y] ToolforgeWebHighErrorRate should not page if a single tool is down
Open, Needs TriagePublic

Assigned To
None
Authored By
fnegri
Jun 21 2026, 9:06 AM
Referenced Files
F91672046: 2026-07-03-114951_2311x1688_scrot.png
Jul 3 2026, 9:50 AM
F91672008: 2026-07-03-114923_3203x1672_scrot.png
Jul 3 2026, 9:50 AM
F90756539: image.png
Jun 27 2026, 3:28 PM
F90754872: image.png
Jun 27 2026, 3:01 PM
F90754804: image.png
Jun 27 2026, 3:01 PM
F90754734: image.png
Jun 27 2026, 3:01 PM
F89794383: Screenshot 2026-06-21 at 11.04.37.png
Jun 21 2026, 9:06 AM
F89793674: Screenshot 2026-06-21 at 10.43.41.png
Jun 21 2026, 9:06 AM

Description

On 2026-06-20, the scholia tool started misbehaving and returning 500 responses:

Screenshot 2026-06-21 at 10.51.53.png (2,248×698 px, 232 KB)

This triggered a page (ToolforgeWebHighErrorRate) because the overall error rate for Toolforge went above 25%:

Screenshot 2026-06-21 at 10.43.41.png (2,336×840 px, 301 KB)

I was paged and could not find a dashboard showing the responses divided by tool, so I had to edit the Grafana query for "Webservice HTTP status codes" in the tool-dashboard dashboard, removing the "sum" to show the status codes divided by tool. This showed the highest number of 500s were coming from scholia. (Edit: I have now saved this Grafana query to a new dashboard at https://grafana.wmcloud.org/d/fnhp8st/tool-error-rates)

I went in to the bastion and found the webservice pod was in CrashLoopBackOff:

fnegri@tools-bastion-15:~$ sudo become scholia
tools.scholia@tools-bastion-15:~$ kubectl get all
NAME                          READY   STATUS             RESTARTS         AGE
pod/scholia-7d59c859d-t62j8   0/1     CrashLoopBackOff   536 (2m5s ago)   5d20h

NAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/scholia   ClusterIP   10.104.107.222   <none>        8000/TCP   4y215d

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/scholia   0/1     1            0           2y253d

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/scholia-5cf649844f   0         0         0       94d
replicaset.apps/scholia-6b49cf594d   0         0         0       40d
replicaset.apps/scholia-6c45778847   0         0         0       39d
replicaset.apps/scholia-6d66647cd4   0         0         0       40d
replicaset.apps/scholia-75795bc585   0         0         0       26d
replicaset.apps/scholia-7bd7d8ff99   0         0         0       40d
replicaset.apps/scholia-7d59c859d    1         1         0       9d
replicaset.apps/scholia-7f5db5864d   0         0         0       40d
replicaset.apps/scholia-86f7954d5f   0         0         0       25d
replicaset.apps/scholia-bd6c94d7     0         0         0       38d
replicaset.apps/scholia-d9b6844c9    0         0         0       32d

Stopping the tool with webservice stop fixed the overall Toolforge Error Rate:

Screenshot 2026-06-21 at 11.04.37.png (2,330×842 px, 189 KB)

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

After a few minutes the webservice is in CrashLoopBackOff again:

tools.scholia@tools-bastion-15:~$ kubectl get all
NAME                           READY   STATUS             RESTARTS      AGE
pod/scholia-7b8d846c5c-wv9h2   0/1     CrashLoopBackOff   5 (64s ago)   6m7s

I stopped it again and opened https://github.com/WDscholia/scholia/issues/2794

Mentioned in SAL (#wikimedia-cloud) [2026-06-21T09:18:49Z] <dhinus> webservice stop (tried restarting, but it keeps crashing) T429738

This triggered again today, around one hour ago, and scholia was stopped (and the alert stopped too).

There's though an increased number of sessions on the frontend, that are hitting now fourohfour:

Sessions on the proxy:

image.png (1,951×362 px, 136 KB)

Fourohfour traffic:

image.png (2,537×737 px, 205 KB)

You can see here on the proxy, that the 500s that trigger the alet (in red) moved to 400s (in orange):

image.png (1,946×351 px, 283 KB)

Another one where you can also see that the traffic on scholia moved to fourohfour, and multiplied at the same time (probably due to retries):

image.png (2,036×770 px, 333 KB)

fnegri updated the task description. (Show Details)

Another one where you can also see that the traffic on scholia moved to fourohfour, and multiplied at the same time (probably due to retries):

Is this chart from one of our dashboards? I could not find it.

I created a new one targeted to this specific issue: https://grafana.wmcloud.org/d/fnhp8st/tool-error-rates

fnegri updated the task description. (Show Details)
dcaro renamed this task from ToolforgeWebHighErrorRate should not page if a single tool is down to [infra] ToolforgeWebHighErrorRate should not page if a single tool is down.Jun 29 2026, 8:19 AM
dcaro renamed this task from [infra] ToolforgeWebHighErrorRate should not page if a single tool is down to [infra,o11y] ToolforgeWebHighErrorRate should not page if a single tool is down.

Indeed now with the work by @taavi on T392356: Replace ingress-nginx before upstream EOL date we do have per-tool status codes as seen by istio, i.e. the metric used in https://grafana.wmcloud.org/d/fnhp8st/tool-error-rates based on istio_requests_total

With that in mind we can do per-tool availability as rate(5xx) / rate(all-codes):

1 - (
sum by (destination_service_namespace) (rate(istio_requests_total{response_code=~"5.."}[5m]))
  /
sum by (destination_service_namespace) (rate(istio_requests_total[5m]))
)

Then I think it makes sense to frame toolforge availability as: max( unavailable tools (i.e. availability < 1) )

To illustrate the example, this is availability during the eqiad incident the other day. Shown here as taking top20 tools just for illustration purposes:

2026-07-03-114923_3203x1672_scrot.png (3,203×1,672 px, 186 KB)

Or taken as the max()

2026-07-03-114951_2311x1688_scrot.png (2,311×1,688 px, 108 KB)

Links respectively: https://w.wiki/R$Fv https://w.wiki/R$Fw

The tool availability metric will need to be a recording rule because istio_requests_total is huge. And the same per-tool availability metric can also feed the KR metrics for webservice unavailability we were talking about yesterday (cc @CCiufo-WMF @aputhin)

Moving the alerting to be based on Istio-level metrics means we lose visibility into any potential connectivity issues between HAProxy and Istio, right?

Maybe we could keep the haproxy alert but with a higher threshold? I opened https://gitlab.wikimedia.org/repos/cloud/toolforge/alerts/-/merge_requests/65 that is also a quick fix if we want to restart Scholia.

To clarify my previous comment: maybe we could keep the haproxy alert at a 50% threshold (or higher), but also have an additional alert based on istio, like the one suggested by @fgiunchedi above.

Mentioned in SAL (#wikimedia-cloud) [2026-07-03T13:59:50Z] <dhinus> "webservice -m 1G python3.9 start" (after increasing the alert threshold in T429738)

Moving the alerting to be based on Istio-level metrics means we lose visibility into any potential connectivity issues between HAProxy and Istio, right?

Yes indeed, if haproxy can't talk to istio at all is I think the most prominent case. The other way around (i.e. istio can't talk to haproxy) should be covered (to be verified) because istio/envoy reports such condition as status flags, I'm assuming as part of a 5xx: https://www.envoyproxy.io/docs/envoy/latest/configuration/advanced/substitution_formatter#config-access-log-format-response-flags (DC I think)

I don't feel strongly either way on which way to go (both alerts, keep the current alert with lower threshold, something else) as long as we're comfortable with it as a paging alert (i.e. high confidence it won't misfire)