') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Support autoscaling the API on GKE by brianvans · Pull Request #95 · braintrustdata/helm · GitHub
Skip to content

Support autoscaling the API on GKE - #95

Merged
brianvans (brianvans) merged 13 commits into
mainfrom
brianvans/support-autoscaling-api-on-gke
Aug 17, 2026
Merged

Support autoscaling the API on GKE#95
brianvans (brianvans) merged 13 commits into
mainfrom
brianvans/support-autoscaling-api-on-gke

Conversation

@brianvans

@brianvansbrianvans (brianvans) commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Adds optional Horizontal Pod Autoscaling on GKE using native AutoscalingMetric support. When turned on, the API scales on CPU, event-loop utilization, and mean event-loop delay (same signals we use on AWS ECS), and Prometheus metrics are enabled automatically. Requires GKE 1.35.1+.

This has a hard requirement on v2.9.0+ of the Braintrust data plane, as this introduced the internal /metrics endpoint capability.

See https://docs.cloud.google.com/kubernetes-engine/docs/how-to/expose-custom-metrics-autoscaling for docs on the GKE preview feature that backs this.

Adds optional Horizontal Pod Autoscaling on GKE using native
AutoscalingMetric support. When turned on, the API scales on CPU,
event-loop utilization, and mean event-loop delay (same signals we use
on AWS ECS), and Prometheus metrics are enabled automatically. Requires
GKE 1.35.1+.
See https://docs.cloud.google.com/kubernetes-engine/docs/how-to/expose-custom-metrics-autoscaling

@erikdwErik Weathers (erikdw) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small follow-ups. Neither blocks merge.

Comment threadbraintrust/templates/api-deployment.yaml Outdated
Comment threadbraintrust/README.md
Comment threadbraintrust/values.yaml Outdated

@erikdwErik Weathers (erikdw) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

Integrate GKE API autoscaling with workload isolation pools so each
rendered API pool gets its own AutoscalingMetric and HPA when enabled.
@brianvans

Copy link
Copy Markdown
ContributorAuthor

I had to change things up a bit for autoscaling of the isolated API pools that were introduced in #97.

See braintrust/examples/google-api-isolation-autoscaling/values.yaml for a minimal example of autoscaling the workload-specific API pools independently

Comment threadbraintrust/examples/google-api-isolation-autoscaling/values.yaml Outdated
Comment threadbraintrust/examples/google-api-isolation-autoscaling/values.yaml Outdated
Comment threadbraintrust/tests/api-autoscaling_test.yaml
Comment threadbraintrust/values.yaml
Comment threadbraintrust/templates/api-hpa.yaml Outdated
Comment threadbraintrust/README.md
Comment threadbraintrust/README.md
Better document hard requirement on v2.9.0 for /metrics endpoint

@erikdwErik Weathers (erikdw) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢 🇮🇹

@brianvans
brianvans (brianvans) merged commit 7f48649 into mainAug 17, 2026
3 checks passed
@erikdw
Erik Weathers (erikdw) deleted the brianvans/support-autoscaling-api-on-gke branch August 18, 2026 00:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@brianvans@erikdw@KevinGreen@soldatchenko