Repository navigation
fix(traefik): allow disabling backend connection reuse for Swarm services - #5702
WilliamAGH wants to merge 2 commits into
Conversation
…ices Traefik pools idle backend connections by dial address, so a connection opened to http://<appName>:<port> stays bound to the task it first reached after Swarm removes that task from the service VIP during a rolling update. Add an application setting, on by default, that when turned off renders an application-owned serversTransport with maxIdleConnsPerHost: -1 and points every generated service for the application at it. Changing the setting rewrites the existing primary and preview route files. Fixes Dokploy#5281 Agent-Session: 9844533d-f186-4fe0-9641-6a1c2b9baf44
The application page refetches every 5 seconds, so resetting the form on every new data object discarded edits made during a deployment. Reset only when a field the form shows changes. Agent-Session: 9844533d-f186-4fe0-9641-6a1c2b9baf44
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f5665e56d1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| delete service.loadBalancer.serversTransport; | ||
| } | ||
| } else { | ||
| service.loadBalancer.serversTransport = transportName; |
There was a problem hiding this comment.
Preserve custom server transports when disabling reuse
When a generated service already references a user-defined serversTransport through the supported application Traefik editor, disabling reuse unconditionally replaces that reference with the generated transport. Options on the custom transport (for example timeouts, proxying, or TLS settings) immediately stop applying, and re-enabling reuse cannot restore the original reference because its name has been lost. Preserve non-owned references or augment their transport instead of overwriting them.
Useful? React with 👍 / 👎.
| if ( | ||
| Object.keys(config.http?.routers ?? {}).length === 0 && | ||
| Object.keys(config.http?.services ?? {}).length === 0 | ||
| ) { | ||
| return; |
There was a problem hiding this comment.
Propagate remote reconciliation read failures
For an application on a remote server, a transient SSH or cat failure is caught by loadOrCreateConfigRemote and returned as the same empty config used for a missing route file. This guard consequently returns successfully after updateApplication has already persisted the new flag, and there is no retry when the server recovers, so existing primary and preview routes keep the old connection-reuse policy while the UI shows the new value. Distinguish a missing file from a failed read and propagate or queue the latter.
Useful? React with 👍 / 👎.
| } else { | ||
| service.loadBalancer.serversTransport = transportName; |
There was a problem hiding this comment.
Custom backend settings disappear
Turning off swarmVipConnectionReuse overwrites any custom serversTransport on generated services. Users can save these references through updateTraefikConfig, so this discards custom timeouts or TLS settings and can break routes that rely on them. Turning reuse back on removes the replacement without restoring the original reference.
Leave services with a different custom transport unchanged, as the PR description promises.
| if ( | ||
| updated && | ||
| previous && | ||
| previous.swarmVipConnectionReuse !== updated.swarmVipConnectionReuse | ||
| ) { |
There was a problem hiding this comment.
Failed route updates cannot retry
updateApplication saves the new value before updating route files, but this comparison skips another attempt once the stored value matches. If the remote server is temporarily unreachable, loadOrCreateConfigRemote returns an empty config and the route update exits without changing anything. Write failures are also caught without being reported.
The save appears successful even though routes still use the old setting, and saving the same value again cannot repair them. Report failures and allow a retry to apply the stored setting.
What is this PR about?
Dokploy routes each application domain to its Swarm service VIP (
http://<appName>:<port>). Traefik pools idle backend connections by dial address, not by the task IP behind the VIP. During a rolling update, a keep-alive connection opened before the update can stay attached to a task that Swarm has already removed from service membership. New connections follow the VIP correctly; pooled ones do not.This PR adds an application setting, Reuse backend connections (Advanced → Cluster Settings), on by default so existing behavior is unchanged. When it is turned off:
serversTransportnamed<appName>-swarm-vipwithmaxIdleConnsPerHost: -1in the application's dynamic config file.<appName>-service-*load balancer references that transport, so Traefik opens a new backend connection for each request and each one goes through the VIP.serversTransportset by hand to a different name is left alone.Changes:
application.swarmVipConnectionReuseboolean column,NOT NULL DEFAULT true, with its drizzle migration. drizzle-kit also emitted thewebServerSettings.whitelabelingConfigdefault thatcanary's schema already declares but no migration had generated yet; I left the generated output unedited.manageDomainapplies the transport when it writes a domain route.updateApplicationrewrites primary and preview route files only when the stored value changes.command, so the switch and the registry select could show stale defaults. Resetting on every refetch would instead discard unsaved edits, because the application page polls every 5 seconds.Reproduction (from #5281):
How I tested it:
pnpm typecheckpasses.viteston__test__/traefik,__test__/drop, and__test__/server/mechanizeDockerContainer.test.ts: 77 tests pass. The newswarm-vip-transport.test.tscovers rendering the transport across several domains, removing it again while keeping a hand-set transport, and not creating a route file for an application without domains.traefik:v3.6.25container with the file provider and atraefik/whoamibackend: with reuse off, two consecutive requests reached the backend from different source ports (new connection each time). AftermanageDomainswitched reuse back on, consecutive requests shared one source port (pooled connection).biome formatreports no changes on the touched files.Checklist
Before submitting this PR, please make sure that:
canarybranch.Issues related (if applicable)
Closes #5281
Screenshots (if applicable)
Fix custom transport loss and failed route update recovery before merging.
Summary
Adds an application switch to disable backend connection reuse for generated Traefik routes.
WilliamAGH explicitly acknowledged keeping the generated branding default change because the existing schema already declares it.
Reviews (1) · Last reviewed commit: "fix(ui): keep unsaved cluster settings a..." · Reviewed by Greptile