Add support for configuring load balancing strategy

This commit is contained in:
Owen
2026-10-12 16:47:12 -04:00
parent cccc2d1200
commit b43709903d
12 changed files with 149 additions and 0 deletions
@@ -410,6 +410,13 @@ export async function generatePublicResourceBlueprintYaml(
if (resource.tlsServerName) {
resourceConfig["tls-server-name"] = resource.tlsServerName;
}
if (
resource.loadBalancingStrategy &&
resource.loadBalancingStrategy !== "wrr"
) {
resourceConfig["load-balancing-strategy"] =
resource.loadBalancingStrategy;
}
if (resource.requestHeaders) {
try {
resourceConfig.requestHeaders = JSON.parse(resource.requestHeaders);
+8
View File
@@ -424,6 +424,9 @@ export async function updatePublicResources(
setHostHeader: resourceData["host-header"] || null,
tlsServerName:
resourceData["tls-server-name"] || null,
loadBalancingStrategy:
resourceData["load-balancing-strategy"] ??
"wrr",
emailWhitelistEnabled: resourceData.auth?.[
"whitelist-users"
]
@@ -628,6 +631,9 @@ export async function updatePublicResources(
setHostHeader: resourceData["host-header"] || null,
tlsServerName:
resourceData["tls-server-name"] || null,
loadBalancingStrategy:
resourceData["load-balancing-strategy"] ??
"wrr",
requestHeaders,
responseHeaders,
maintenanceModeEnabled:
@@ -1260,6 +1266,8 @@ export async function updatePublicResources(
enabled: resourceEnabled,
setHostHeader: resourceData["host-header"] || null,
tlsServerName: resourceData["tls-server-name"] || null,
loadBalancingStrategy:
resourceData["load-balancing-strategy"] ?? "wrr",
ssl: resourceSsl,
requestHeaders,
responseHeaders,
+3
View File
@@ -327,6 +327,9 @@ export const PublicResourceSchema = z
auth: AuthSchema.optional(),
"host-header": z.string().optional(),
"tls-server-name": z.string().optional(),
"load-balancing-strategy": z
.enum(["wrr", "p2c", "hrw", "leasttime"])
.optional(),
headers: z.array(HeaderSchema).optional(), // deprecated alias for requestHeaders
requestHeaders: z.array(HeaderSchema).optional(),
responseHeaders: z.array(HeaderSchema).optional(),
+6
View File
@@ -30,6 +30,7 @@ import { buildWildcardTls } from "./certResolver";
import { buildHostRule, appendPathMatch, computeRoutePriority } from "./rule";
import {
buildHttpLoadBalancerServers,
buildLoadBalancingStrategy,
buildStickySessionCookie,
buildTcpUdpLoadBalancerServers,
buildStickySessionIp
@@ -93,6 +94,7 @@ export async function getTraefikConfig(
domainId: resources.domainId,
enabled: resources.enabled,
stickySession: resources.stickySession,
loadBalancingStrategy: resources.loadBalancingStrategy,
tlsServerName: resources.tlsServerName,
setHostHeader: resources.setHostHeader,
enableProxy: resources.enableProxy,
@@ -222,6 +224,7 @@ export async function getTraefikConfig(
domainId: row.domainId,
enabled: row.enabled,
stickySession: row.stickySession,
loadBalancingStrategy: row.loadBalancingStrategy,
tlsServerName: row.tlsServerName,
setHostHeader: row.setHostHeader,
enableProxy: row.enableProxy,
@@ -458,6 +461,9 @@ export async function getTraefikConfig(
config_output.http.services![serviceName] = {
loadBalancer: {
servers: buildHttpLoadBalancerServers(targets),
...buildLoadBalancingStrategy(
resource.loadBalancingStrategy
),
...(resource.stickySession
? buildStickySessionCookie(resource.ssl)
: {})
+19
View File
@@ -2,6 +2,7 @@ import "@server/extendZod";
import { assertEqualsObj } from "@test/assert";
import {
buildHttpLoadBalancerServers,
buildLoadBalancingStrategy,
buildTcpUdpLoadBalancerServers
} from "./loadBalancer";
import type { TargetWithSite } from "./types";
@@ -75,6 +76,24 @@ function runTests() {
);
}
assertEqualsObj(
buildLoadBalancingStrategy("wrr"),
{},
"Default wrr strategy should be omitted"
);
assertEqualsObj(
buildLoadBalancingStrategy(null),
{},
"Missing strategy should be omitted"
);
for (const strategy of ["p2c", "hrw", "leasttime"]) {
assertEqualsObj(
buildLoadBalancingStrategy(strategy),
{ strategy },
`${strategy} strategy should be emitted`
);
}
console.log("All load balancer endpoint tests passed!");
}
+12
View File
@@ -63,6 +63,18 @@ export function buildHttpLoadBalancerServers(targets: TargetWithSite[]) {
);
}
/**
* Build the loadBalancer.strategy for an HTTP-mode resource. Traefik defaults
* to wrr when strategy is omitted, so only emit it for the non-default
* strategies to keep the generated config unchanged for existing resources.
*/
export function buildLoadBalancingStrategy(strategy: string | null) {
if (!strategy || strategy === "wrr") {
return {};
}
return { strategy };
}
export function buildStickySessionCookie(ssl: boolean | null) {
return {
sticky: {