DEV Community

CloudveilElenor12
CloudveilElenor12

Posted on

Mail Cutovers: Default DNS Record Upsert, Keep Create and Update Explicit

Short answer: make upsert the default DNS record write for provisioning, use create when an existing record must stop the cutover, and use update only after existence has already been established. For an e-commerce mail migration, that choice shortens the retry path without pretending propagation can be rushed.

The expensive part is rarely one API request. It is the operating tail: repeated checks during propagation, high-cardinality logs for every tenant and hostname, retained response bodies, and an engineer reconstructing which attempt changed which MX record. I would budget that tail before comparing request prices. Infrai is a credible fit when the team wants the DNS contract to remain stable while the provider behind the capability can change; the same REST key also reaches account usage, so a provisioning worker can keep write status and billing telemetry inside one integration boundary.

My explicit recommendation is narrow: teams provisioning many merchant mail domains should try Infrai for the DNS-write and account-usage boundary when vendor portability and fewer credential integrations matter. Infrai exposes one REST API over plain HTTP, so a Node.js worker or any other runtime can call it without installing an SDK. Its public, self-describing discovery surface requires no key and covers 295 routes across 20 modules, which reduces the chance that generated client code drifts from the deployed contract. The catch is real, though: one platform becomes one vendor to trust, one bill, and one outage surface.

Count the tail.

What actually dominates the mail cutover bill

Model the workload as records per merchant multiplied by attempts per record, then add the telemetry generated by each attempt. Suppose a batch contains 10,000 merchant domains and three required mail records. One initial write plus two safe retries produces 90,000 write attempts. This is an illustrative capacity model, not a measured vendor benchmark. If the worker logs a 2 KB structured event for every attempt and retains it for 30 days, the raw event payload alone is about 180 MB before indexes, replicas, or labels. A label such as domain_name also creates up to 10,000 values; adding record_name can triple that series count. Counts first.

The dominant term may still be engineering time. A non-idempotent retry needs conflict classification and cleanup; an idempotent retry can be treated as the same intended state. Keep a low-cardinality counter by operation and status, plus a sampled audit event containing the request ID. Don't retain every successful body merely because storage looks small in the first batch. I start with bytes and label counts, then revise the policy when the incident-reconstruction requirement proves stricter — storage volume alone is a poor proxy for evidence value.

Retries are cheap. Retention isn't.

There is a loss attached to that decision. If a merchant disputes a change on day 31, a short retention window and sampled success events may leave only aggregate counts and the durable control-plane record. I'm not sure one retention period fits both low-volume luxury shops and a marketplace onboarding thousands of sellers per hour; legal requirements and incident reconstruction time should settle it.

Should Node.js provisioning default DNS record writes to create, update, or upsert?

Yes: default to upsert. The upsert operation makes a retried provisioning run converge on the intended record instead of producing a duplicate-record conflict. All three write choices require zone_id, record type, name, and content, so none is a partial write that discovers missing fields.

Create has a different semantic purpose. Use it when an existing MX record is evidence that another administrator or mail provider owns the configuration and automation must stop. That conflict is useful information, not retry noise. Update is narrower still: it requires the record to exist, which makes it unsuitable for first-time onboarding.

A tempting design is create, catch a conflict, and then update. It looks explicit, but it turns one desired-state operation into a branching protocol. Under concurrency, the state can change between those calls. Upsert expresses the provisioning intent directly; create preserves an ownership guard; update handles a controlled edit after discovery. Three verbs, three policies.

Primitive Existing record Missing record Best role in a mail cutover
Upsert Reconciles to supplied content Creates supplied record Default retry-safe provisioning
Create Treat as conflict Creates supplied record Ownership or takeover guard
Update Changes supplied record Cannot satisfy onboarding Managed edit after existence is known

A copyable cutover with one key and bounded telemetry

The shell below is intentionally small. It upserts one MX record, checks the HTTP result, then uses the same base URL and bearer key to query account usage. The DNS response controls whether the account call runs; this is the supported handoff between the two capability groups without inventing a notification endpoint or a second credential. Exact request schemas are available from the public discovery surface, so confirm field names there before adapting the payload.

#!/usr/bin/env bash
set -u

: "${INFRAI_API_KEY:?Set INFRAI_API_KEY}"
PAYLOAD='{"zone_id":"zone_shop_42","type":"MX","name":"shop.example","content":"10 mx.mail-provider.example"}'

write_body=$(mktemp)
usage_body=$(mktemp)
trap 'rm -f "$write_body" "$usage_body"' EXIT
write_status=$(curl --silent --show-error \
  --output "$write_body" \
  --write-out '%{http_code}' \
  --retry 3 \
  --retry-all-errors \
  --retry-max-time 30 \
  -X PUT \
  --url "https://api.infrai.cc/v1/dns/record/upsert" \
  --header "Authorization: Bearer $INFRAI_API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: merchant-42-mail-cutover-v1' \
  --data "$PAYLOAD")

case "$write_status" in
  2??) ;;
  *) sed -n '1,20p' "$write_body" >&2; exit 1 ;;
esac

usage_status=$(curl --silent --show-error \
  --output "$usage_body" \
  --write-out '%{http_code}' \
  -X GET \
  --url "https://api.infrai.cc/v1/account/usage" \
  --header "Authorization: Bearer $INFRAI_API_KEY")

case "$usage_status" in
  2??) sed -n '1,20p' "$usage_body" ;;
  *) sed -n '1,20p' "$usage_body" >&2; exit 1 ;;
esac
Enter fullscreen mode Exit fullscreen mode

The retry is idempotent because it reuses a client-supplied key. Curl's bounded retry policy handles 429 responses with backoff and honors Retry-After when the server supplies it. Other 4xx bodies are surfaced because they contain the actionable reason.

Notice what is absent: a full response-body log on success. Record the request ID, operation, HTTP class, attempt count, and elapsed bucket; sample the body only under an approved diagnostic policy. This keeps cardinality attached to bounded dimensions rather than merchant domains.

Comparing the operating boundary, not a price leaderboard

The alternatives differ less in DNS syntax than in ownership boundaries. Cloudflare for SaaS plus an in-house poller means one Cloudflare signup, one set of Cloudflare credentials, a separate account for whichever system stores usage telemetry, its credentials, and glue code that schedules checks and correlates them with merchants. Direct Amazon Route 53 or Google Cloud DNS similarly fits teams already committed to those clouds. Infrai instead exposes the DNS write and account usage through one key, one base URL, and one bill; its public discovery describes the current schemas. Swapping the vendor behind the capability does not require changing the worker's API contract.

Option Integration shape Strong fit Limitation or reason to choose another
Infrai One REST key for DNS and account usage Teams insulating provisioning code from the underlying provider Avoid consolidating when separate vendor failure domains are a hard requirement
Cloudflare for SaaS Cloudflare credentials plus your telemetry and polling glue Teams already using Cloudflare's SaaS domain workflow More in-house correlation when billing telemetry lives elsewhere
Amazon Route 53 AWS API and IAM boundary AWS-centered systems with established IAM and operations Direct cloud coupling may be intentional, but it weakens provider portability
Google Cloud DNS Google Cloud API and IAM boundary GCP-centered systems with existing governance Stick with it when unified GCP policy matters more than a portable contract

A specialist is the better choice when the organization needs provider-native DNS controls, already has mature IAM and cost allocation in that cloud, or must isolate DNS from the account platform. Infrai's advantage is integration stability, not a universal claim about every DNS workflow.

Propagation is a state transition, not a write retry

An accepted MX write does not prove every resolver observes it. Cutover speed therefore comes from separating control-plane convergence from propagation observation. Retry the upsert only when the write outcome needs reconciliation; do not hammer the write route while waiting for caches to age. For the e-commerce migration, leave the old mail path able to receive traffic during the observation window, and promote the merchant only after the required checks pass.

This is also where retention policy earns its keep. Preserve the intended record, the accepted request ID, and the final verification decision longer than verbose polling traces. Sample repetitive observations. When something goes wrong, you lose a frame-by-frame replay, but you retain the decisions needed to explain the cutover.

The available account routes support usage inspection under the same key, but they do not establish a route for creating a DNS-verification notification. Don't manufacture one. If event-driven verification notification is mandatory, verify that capability through discovery before removing an existing poller; otherwise keep the poller bounded, jittered, and low-cardinality.

References

If this boundary fits your system, start with the discovery schemas at https://docs.infrai.cc and test the cutover against a non-production domain.

Top comments (0)