diff --git a/lib/admin/list.ts b/lib/admin/list.ts index fd7e972..1398aa7 100644 --- a/lib/admin/list.ts +++ b/lib/admin/list.ts @@ -77,11 +77,15 @@ type TunnelRow = TunnelJoinRow & { const USER_SCAN_MAX_PAGES = 50; const USER_SCAN_PER_PAGE = 1000; -// Resolve tunnel owner emails a few at a time rather than all at once: a large -// concurrent burst of getUserById calls self-inflicts an upstream throttle -// (truncated/empty bodies) that even per-call retries can't fully escape, which -// is what intermittently rendered owner_email as "—" under load. -const OWNER_EMAIL_CONCURRENCY = 4; +// Resolve tunnel owner emails a couple at a time rather than all at once. The +// upstream tolerates a small concurrent burst, but a large fan-out of +// getUserById calls (one per row, all in flight) trips an upstream throttle that +// truncates the tail of the burst into empty/partial bodies. Those truncations +// arrive faster than the per-call retry window can clear them, so a few rows +// were deterministically rendered as "—" on every list load. A low concurrency +// keeps each lookup inside the throttle allowance; measured 0 failures at 2 and +// consistent truncations at 4, so we stay conservative here. +const OWNER_EMAIL_CONCURRENCY = 2; function userSortValue(u: User, sort: UserSort): string | number { switch (sort) {