Skip to content

fix: Keep external-dns running through large DNS change batches - #10

Merged
ecv merged 1 commit into
mainfrom
fix/apply-changes-deadline
Sep 26, 2026
Merged

ecv merged 1 commit into
mainfrom
fix/apply-changes-deadline

Conversation

@scotwells

Copy link
Copy Markdown
Contributor

Summary

External-dns crash-loops in production whenever it sends a large batch of DNS changes, because the provider closes the connection without answering once a batch runs past 30 seconds.

External-dns reads a dropped connection as fatal and exits, even though the provider keeps applying the changes in the background.

Large batches now either finish, applied several changes at a time, or stop at a configurable limit and answer with an error that names the limit. External-dns treats that error as retryable and picks up the remaining changes on its next sync instead of restarting.

The limit defaults to five minutes and four parallel changes, and both are adjustable at startup.

Test plan

  • A batch slower than the old 30 second window completes and external-dns sees success
  • A batch that overruns the limit gets a 503 naming the limit, which the external-dns v0.15 client reports as a retryable error rather than a dropped connection
  • A record deleted and recreated in the same batch ends up with the new value
  • Build, vet, unit tests with the race detector, and lint pass

Fixes #4

A POST /records that ran past the webhook server's 30s write timeout had
its connection closed with no response while the handler kept applying
changes. ExternalDNS saw a transport EOF, which it treats as fatal, and
exited. Production crash-loops on any batch of roughly 40 or more
changes, since each change costs 2-3s against the Datum DNS API and was
applied one at a time.

Key changes:
- Bound each apply by --apply-timeout (default 5m) and derive the server
  write timeout from it with 30s of headroom, so the handler always
  answers before the server gives up on the connection
- When the deadline is reached, stop starting new changes and return a
  503 that says how many changes were attempted and which flag raises
  the limit; ExternalDNS treats a 5xx as a soft error and retries on its
  next sync instead of exiting
- Apply changes within each phase in parallel, bounded by
  --apply-concurrency (default 4)
- Run a delete before the creates when the same record set is recreated
  in the batch; other deletes still run last, so replacements are made
  before old records are removed
- Recover a panic in a single change so it fails that change instead of
  the process

Tests drive the real ExternalDNS v0.15 webhook client against the
server, so the soft-error contract is checked against the code that
decides whether ExternalDNS exits.
@ecv
ecv marked this pull request as ready for review September 26, 2026 22:02
@ecv
ecv merged commit 6a8e89e into main Sep 26, 2026
9 of 11 checks passed
@ecv
ecv deleted the fix/apply-changes-deadline branch September 26, 2026 22:02
Sign up for free to 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.

A large record batch closes the connection and kills external-dns

2 participants