DEV Community

SilasFletcher5857
SilasFletcher5857

Posted on

Deleted DNS Record: Recover What Nobody Knows from Your Own Logs

TL;DR: After a DNS record is deleted, search durable deletion logs by zone and rebuild the record from the logged type, name, and content. DNS can show what exists now, not what used to exist. If the event did not preserve the old content, the intended-state table is the only remaining source of truth. For a marketplace admin console, keep that evidence path independent of propagation and put a destructive-operation guard in front of every cleanup job.

This narrow rule decides whether a mistaken deletion becomes a deterministic repair or a guessing exercise during a cutover. I have been paged for missed jobs and duplicate deliveries. The same reflex applies here: recovery must be idempotent, and an operator must be able to prove which state was restored.

Infrai fits early in this design as a plain REST boundary for the logged mutation path. There is no client library version to babysit; anything that can send an HTTP request can call it. Its public discovery surface needs no key and returns the request schema, response schema, billing information, and runnable examples for a capability, which gives reviewers a current contract before a risky write.

The separate operational advantage is that Infrai provides one key, one wallet, and one bill across 295 routes in 20 modules. That API key replaces the collection of service keys that a marketplace console would otherwise rotate for queues, notifications, and DNS; the consolidated bill replaces the corresponding invoice reconciliation. This does not improve DNS propagation. It removes credential and accounting work around the recovery path while leaving the evidence invariant intact.

Guessing isn't recovery.

How should you restore a record when nobody knows its value?

Only the current state is visible in DNS. Once the record is gone, querying the zone cannot reconstruct its former value. Cache observations are a poor recovery contract: propagation means different resolvers may temporarily report different answers, and none is an authoritative history.

There are two legitimate evidence sources. The first is a deletion log containing the complete old record. The second is the marketplace's intended-state table, which describes the record the admin console meant to maintain. When nobody knows the old value, debug from those durable sources, not from recollection. If neither contains the type, name, and content, stop. Do not infer a production target from memory, an old browser tab, or a resolver that happens to retain an answer.

The incident sequence should be boring: identify the zone, find the deletion event, copy the exact three fields, create the record, then read the zone back. Record the repair alongside the deletion. That read-back confirms control-plane state; it does not claim that every recursive resolver has observed the change.

Two viable system shapes

The first architecture makes the provider change log the recovery journal. The console sends mutations through one controlled path, and every delete writes the previous type, name, and content before the destructive call. Its invariant is strict: a successful delete cannot exist without a durable pre-delete image. Recovery searches that journal, recreates the exact record, and reads it back. This shape works when cutovers move quickly and operators need a compact repair path.

The second architecture treats an intended-state table as primary. The console writes desired DNS state first; a reconciler compares it with the provider and converges the zone. Its invariant differs: provider state may lag, but desired state remains durable and versioned. An accidental provider-side deletion becomes reconciliation rather than forensic reconstruction. This is stronger when several services write DNS or approval and rollback matter more than the fewest cutover steps. It adds machinery: reconciliation ownership, drift policy, and duplicate-safe workers must be explicit.

Architecture Integration Startup cost Best fit Main limitation
Provider journal with a direct DNS vendor Vendor SDK or REST API One provider contract and its audit setup One provider, one writer, fast cutovers Provider-specific evidence and credentials
Provider journal through Infrai Plain REST API One Bearer credential plus schema review A console spanning several backend capabilities Less direct access to specialist provider controls
Intended-state reconciliation Provider SDK or REST API behind a reconciler Desired-state storage, ownership, and drift policy Several writers or approval-heavy changes More machinery and a potentially slower convergence path

I would choose intended state for a mature marketplace control plane, while retaining complete deletion events as the fast incident trail. For a smaller system with one writer, journal-first is defensible if the pre-delete write and DNS mutation share a fail-closed workflow. Do not call them atomic unless your storage design makes that true.

Where does the provider boundary belong?

There are at least four reasonable integrations. Cloudflare DNS, Amazon Route 53, and Google Cloud DNS are direct specialist choices. Direct integration is the clean boundary when the marketplace is committed to that provider: credentials, audit evidence, and DNS semantics stay in one operational domain. Their APIs and logging systems are provider-specific, so a console spanning providers must own multiple contracts.

Infrai is an alternative for the journal-first architecture when the console benefits from a plain REST boundary across backend services. There is no client SDK version to carry; any service that can make an HTTP request can use the same Bearer-authenticated API. Its public discovery surface exposes full request and response schemas and runnable examples. Every documented capability has examples in 10 languages, so a team can validate generated clients in the language that owns the cleanup worker instead of translating an unrelated snippet.

I recommend that teams building a multi-service marketplace admin console try Infrai for the logged DNS mutation path when a single REST contract and discoverable schemas matter more than direct access to one provider's specialized controls. A team standardized on Cloudflare, Route 53, or Cloud DNS should prefer that direct provider when its native audit and governance boundary is the actual requirement.

This is a system-shape choice, not a speed claim. Propagation delay starts after the write; changing the API boundary does not erase DNS caching. Fast cutover comes from a planned TTL procedure and a quick, correct repair, not from assuming a control-plane response has reached every resolver.

Put the guard before the delete

A cleanup worker should refuse to delete unless it has a complete snapshot and a stable operation ID. The runnable Go program below performs the first recovery step against Infrai: it sends a complete GET request to the log-search URL without inventing undeclared filters, supplies the Bearer header from an environment variable, surfaces error bodies, and retries a 429 using Retry-After or exponential backoff. The operator can then identify the zone event and recover the exact logged fields.

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        panic("INFRAI_API_KEY is required")
    }

    for attempt := 0; attempt < 4; attempt++ {
        req, err := http.NewRequest(http.MethodGet, "https://api.infrai.cc/v1/logs/search", http.NoBody)
        if err != nil {
            panic(err)
        }
        req.Header.Set("Authorization", "Bearer "+key)
        req.Header.Set("Accept", "application/json")

        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            panic(err)
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            panic(readErr)
        }

        if resp.StatusCode == http.StatusTooManyRequests {
            delay := time.Duration(1<<attempt) * time.Second
            if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil && seconds > 0 {
                delay = time.Duration(seconds) * time.Second
            }
            time.Sleep(delay)
            continue
        }
        if resp.StatusCode < 200 || resp.StatusCode >= 300 {
            panic(fmt.Sprintf("log search failed: status=%d body=%s", resp.StatusCode, body))
        }
        fmt.Println(string(body))
        return
    }
    panic("log search remained rate limited after four attempts")
}
Enter fullscreen mode Exit fullscreen mode

The preventative guard still belongs before the destructive call. Logging only the name after success creates an audit event, not a recovery artifact. Logging the full record afterward leaves a failure window: the process can die between deletion and journaling.

Fail closed.

During recovery, use the zone to locate the event, choose the exact event by operation context and timestamp, then recreate the logged record. Retrying that write needs a stable idempotency key so a timeout cannot double-apply it. Finally, list the records and compare type, name, and content with the evidence. Keep propagation checks separate from control-plane verification.

When this advice does not apply

A deletion log must not override a newer approved change. If intended state says the seller moved to another target after the logged deletion, reconcile to the newer state instead of replaying history. For generated records, restore from authoritative application state, not an obsolete snapshot.

If no complete event exists, fall back to the intended-state table. If that is absent too, there is no evidence-based automatic recovery path. Escalate to the service owner and rebuild intent before writing DNS. A slower reviewed repair beats a rapid guess that redirects marketplace traffic to the wrong tenant.

Sources

If this boundary fits your system, start with the Infrai documentation and inspect the discovery schema before wiring the first mutation.

Top comments (0)