Skip to content

feat(p/LUADNS): batch record changes into bulk API calls - #5047

Open
rootful wants to merge 3 commits into
DNSControl:mainfrom
rootful:luadns-batch-record-changes
Open

rootful wants to merge 3 commits into
DNSControl:mainfrom
rootful:luadns-batch-record-changes

Conversation

@rootful

@rootful rootful commented Oct 27, 2026

Copy link
Copy Markdown
Member

LuaDNS provider called CreateManyRecords, UpdateManyRecords, DeleteManyRecords, but didn't batch RRset changes. This PR fixes that.

I ran the normal tests, integration tests, and tried it on my real zones. I can confirm it is working as intended.

## Problem

The provider used diff2.ByRecordSet and turned every change into its own
correction, so each correction called CreateManyRecords,
UpdateManyRecords or DeleteManyRecords with the records of a single
recordset (usually one record). A zone with N changed recordsets cost N
requests, all serialized through the 4 req/s rate limiter.

## Fix

GetZoneRecordsCorrections now collects the changes by kind and emits
one correction per bulk request: all deletes, then all updates, then all
creates. Keeping deletes ahead of creates preserves diff2's guarantee
that a label's old records are removed before a conflicting new record
(A -> CNAME) is created.

- At most 100 RRs per request (maxBatchRRs). LuaDNS documents no limit;
  this is a conservative guess.
- A recordset is never split across requests, because UpdateManyRecords
  replaces everything stored for each (name, type) it receives. An
  oversized recordset gets a request of its own.
- Updates and deletes keep the 500 retry from DNSControl#5042. Creates are still
  not retried, but a failed create request now fails up to 100 records
  instead of one recordset.
- The per-request Msg is the joined per-change messages, so preview
  output and report counts are unchanged.

## Testing

- `go test ./providers/luadns ./pkg/diff2 ./commands` passes. New tests
  run GetZoneRecordsCorrections against a fake LuaDNS server and check
  request count, endpoints, bodies, kind order, chunking, and the retry
  policy.
- Live LuaDNS integration groups 11, 12, 15, 16, 17, 31, 32 and 35
  pass. Group 38 is skipped for LUADNS by its only() filter. No live
  group sends more than 100 RRs in one request, so chunk splitting is
  covered only by the fake-server test.

@TomOnTime TomOnTime left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I love the performance improvement from batching requests but I do have a concern.

Diff2 very carefully orders the instructions using a much more sophisticated algorithm than simply doing deletes before creates.

I wonder if it would be better to batch runs of the same type of instruction.

For example, if the instructions are info add add add delete add add add... it could batch the two groups of adds.

Does that sound viable?

(Writing in my phone. I'm hope this all makes sense)

TomOnTime and others added 2 commits October 28, 2026 12:05
Review feedback on DNSControl#5047: diff2 orders changes with a dependency graph
(pkg/dnssort), not just deletes before creates, so collecting all
deletes, then updates, then creates could reorder them. Repointing a
CNAME at a new host is the clearest case: diff2 creates the host,
changes the CNAME, then deletes the old host, but the grouped version
sent delete, update, create.

Only consecutive changes of the same kind are now merged into one
request, and a REPORT ends a run. The order that reaches the API is
exactly diff2's. The 100-RR limit, recordset-never-split rule and the
500 retry policy are unchanged.

Tests: the kind-grouping test is replaced by one that expects adjacent
runs (create, update, delete, create, delete, create), and a new test
covers the CNAME repoint order. Both failed against the grouped
implementation.
@rootful

rootful commented Oct 29, 2026

Copy link
Copy Markdown
Member Author

I pushed the fix for that but forgot to mention it, my bad

@TomOnTime

Copy link
Copy Markdown
Collaborator

This makes the pager101 test a lot faster (5 seconds instead of 50 seconds). However if I enable the pager601 test, I get

    helpers_integration_test.go:237: Forbidden: Max records reached, please access account settings page to upgrade your package

Please enable pager601, pager1201, batchRecordswithOthers in integrationTest/integration_test.go and make sure they all pass.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants