health: dedicated 100/1000 rate limit for the redesigned SPA
Some checks failed
ci/woodpecker/push/default Pipeline failed

Viktor hit 429s browsing the redesigned health app. The default shared limiter
is 10 req/s / burst 50, but each page load is the shell (JS chunks + two
self-hosted Geist woff2) plus a 5-8 call API burst, so fast tab-to-tab
navigation from one client IP overruns burst 50 — Traefik 429s the tail and the
affected cards/pages render empty.

Give health its own limiter (average 100, burst 1000) and skip the default,
exactly as tripit/immich/actualbudget/ha-sofia already do for the same
parallel-burst pattern. Attached via the ingress_factory escape hatch
(skip_default_rate_limit + extra_middlewares).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Viktor Barzin 2026-06-14 13:01:14 +00:00
parent 6dc77f4612
commit 086ff85911
2 changed files with 30 additions and 0 deletions

View file

@ -344,6 +344,31 @@ resource "kubernetes_manifest" "middleware_tripit_rate_limit" {
depends_on = [helm_release.traefik]
}
# Health-specific rate limit. The redesigned, data-dense SPA loads the shell
# (JS chunks + two self-hosted Geist woff2) plus a 5-8 call API burst per page,
# and fast tab-to-tab navigation from one client IP blows past the default
# 10/50 limiter 429ing the tail so cards/pages render empty (fifth instance
# of the burst pattern, after ha-sofia, ActualBudget, noVNC and tripit). Burst
# absorbs a couple of full page loads back-to-back.
resource "kubernetes_manifest" "middleware_health_rate_limit" {
manifest = {
apiVersion = "traefik.io/v1alpha1"
kind = "Middleware"
metadata = {
name = "health-rate-limit"
namespace = kubernetes_namespace.traefik.metadata[0].name
}
spec = {
rateLimit = {
average = 100
burst = 1000
}
}
}
depends_on = [helm_release.traefik]
}
# Compress responses to clients at the entrypoint level (outermost).
# Applied at websecure entrypoint so all responses get compressed.
# Uses includedContentTypes (whitelist) instead of excludedContentTypes: