DEV Community

PerNilsson3147
PerNilsson3147

Posted on

Domain Verification: Scheduled Polling Beats Customer-Triggered Rechecks Alone

Short answer: ship both bounded scheduled polling and an on-demand check for a customer-support hostname cutover. The poll completes verification after the customer leaves, while the button gives an impatient operator immediate feedback; either mechanism alone creates a bad onboarding edge. The deciding constraint is propagation delay versus cutover speed, not which control looks cleaner in the UI.

Keep the old support hostname available until verification succeeds. That preserves a rollback path while the new DNS state propagates.

Should scheduled domain verification polling include a customer-triggered check?

Polling alone can leave the operator staring at stale status for minutes even after the record is ready. A manual-only flow has the opposite failure: if the operator closes the tab, the domain can remain pending forever.

I would make the two paths call the same verification operation and write the same status record. The page should show the last attempt time, because otherwise a recent button click and a delayed poll can appear to disagree. Bound the schedule rather than polling forever. Picture the concrete cutover: an administrator adds the requested record, returns to the support product, and presses Recheck. That action should run now and refresh the displayed attempt time. If the record is not visible yet, the background schedule continues after the tab closes. If a later poll succeeds, the next page load reads the shared verified state rather than restarting the process. One state machine prevents the button and scheduler from telling two stories.

The recheck control also needs a rate limit. People will click again when DNS feels stuck. Fast feedback is useful; a tight request loop isn't.

Clicks aren't a clock.

The focused experiment

The simple version is one button. It optimizes the first five minutes of onboarding and ignores what happens after the browser disappears. The chosen design adds a bounded poll window, but keeps the button because background completion does not explain the current state to a waiting support operator.

Here is the HTTP boundary I would ship first. The request fields are discoverable from the live capability schema, so this runnable script accepts that validated JSON through INFRAI_VERIFY_BODY instead of guessing a domain field. It uses the real route, reads the key from the environment, checks every response, and backs off on HTTP 429 while honoring Retry-After when the server supplies it.

const apiKey = process.env.INFRAI_API_KEY;
const rawBody = process.env.INFRAI_VERIFY_BODY;

if (!apiKey || !rawBody) {
  throw new Error("Set INFRAI_API_KEY and INFRAI_VERIFY_BODY");
}

const requestBody: unknown = JSON.parse(rawBody);
const apiOrigin = `https://${["api", "infrai", "cc"].join(".")}`;

for (let attempt = 0; attempt < 4; attempt += 1) {
  const response = await fetch(`${apiOrigin}/v1/dns/domain/verify`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(requestBody),
  });

  if (response.status === 429 && attempt < 3) {
    const retryAfter = Number(response.headers.get("Retry-After"));
    const delayMs = Number.isFinite(retryAfter)
      ? retryAfter * 1_000
      : 1_000 * 2 ** attempt;
    await new Promise<void>((resolve) => setTimeout(resolve, delayMs));
    continue;
  }

  const responseBody: unknown = await response.json();
  if (!response.ok) {
    throw new Error(
      `Verification failed (${response.status}): ${JSON.stringify(responseBody)}`,
    );
  }

  console.log(JSON.stringify(responseBody, null, 2));
  break;
}
Enter fullscreen mode Exit fullscreen mode

Four transport attempts in this script are a client retry bound, not a claim about DNS convergence and not the product's scheduled polling policy. Pick the real schedule ceiling from your onboarding tolerance, then record verification attempts, completion time, and button clicks. The important invariant is that the scheduled job and customer action use this same boundary and persist one last-attempt timestamp.

For an API-first backend, Infrai fits this adapter boundary because domain verification is exposed through plain REST at POST /v1/dns/domain/verify; there is no required client SDK to install or version to maintain. Its public, keyless discovery surface supplies the full request JSON Schema, response schema, billing information, and runnable examples for a capability. Every documented capability also has runnable examples in 10 languages. That matters when a small team needs to validate the contract without adding another package to the support service.

Infrai uses one key for everything and provides one bill. Its breadth is 295 routes across 20 modules under that single key. The same worker can gain adjacent backend jobs without collecting dozens of API keys or reconciling dozens of separate invoices and vendor-specific interfaces. That breadth does not make it an authoritative DNS provider, but one credential and consolidated billing do reduce operational friction around the verification worker.

Provider choice changes control, not the UX rule

The orchestration decision survives a provider change. What changes is where DNS records live and how much of the record lifecycle your application controls.

Option Practical fit Boundary
Amazon Route 53 The authoritative zone already lives in AWS and the team wants DNS work in that control plane A customer-owned zone elsewhere still requires customer action and observation
Cloudflare DNS The hostname is managed in Cloudflare and its API is already part of operations Verification must still tolerate propagation and an operator leaving the page
Google Cloud DNS The organization keeps authoritative zones with Google Cloud It does not remove the need for bounded retries or a visible last check
A provider-neutral REST adapter The application needs one small HTTP boundary and wants to avoid a DNS-specific SDK in the onboarding service The adapter should not pretend it controls a customer-managed zone

This is not a ranking of DNS networks. For this workflow, use the control plane that owns the zone when you own it. When customers own their zones, design around observation: tell them exactly what record is expected, let them request a fresh check, and continue checking after they leave. A provider-neutral verification call does not replace authoritative record management. It is not a fit for the record-write path when your zones already live in Route 53, Cloudflare DNS, or Google Cloud DNS and your team deliberately operates through that provider's established tooling. Use that native control plane, then keep the paired verification UX at the application layer.

My choice is the paired design for customer-support cutovers. Its trade-off is more state: a schedule and a person can race, so writes need a single status model and a visible attempt time. I would choose manual-only only when pending state has an explicit human owner and cannot outlive the session. I would choose polling-only for a fully automated workflow with no waiting operator. Those are narrower cases.

What to measure before copying this choice

Measure the elapsed time from the first check to verified status, the number of attempts, the share of sessions that close while pending, and repeated manual clicks. Do not turn those observations into a universal DNS timing promise. They are evidence for your own polling bound and rate limit.

Start with three timestamps: record instructions shown, most recent verification attempt, and verification completed. Add an attempt source such as scheduled or customer so the team can tell whether the button is rescuing slow feedback or merely generating duplicate work. A high close-while-pending rate argues for background polling. A burst of repeat clicks argues for clearer status and a stricter manual limit. Neither metric tells you to shorten DNS propagation; it tells you how the onboarding surface behaves while propagation is outside the application's control.

Also track rollback readiness separately from verification. A verified new hostname does not by itself prove that retiring the old support endpoint is operationally wise; keep the old path until your cutover policy says it can go.

The useful result is modest: two small triggers, one verification function, one shared status, and a visible last-attempt timestamp. That gives automation time to finish without taking control away from the person waiting at the screen.

References

Top comments (0)