package app import "time" type resolverJobContext struct { domains []string metaSpecial []string staticLines []string wildcards wildcardMatcher cfg dnsConfig domainCache domainCacheState ptrCache map[string]any now int precheckStatePath string precheckEnvForced bool precheckFileForced bool tuning resolverRuntimeTuning cacheSourceForHost func(string) domainCacheSource cooldown *dnsRunCooldown timeoutRecheck resolverTimeoutRecheckStats } func runResolverPipeline(ctx *resolverJobContext, res *resolverResult, logf func(string, ...any)) { if ctx == nil || res == nil { return } start := time.Now() planning := buildResolverPlanning( ctx.domains, ctx.now, ctx.tuning.TTL, ctx.tuning.PrecheckDue, ctx.tuning.PrecheckMaxDomains, ctx.tuning.StaleKeepSec, ctx.tuning.NegTTLNX, ctx.tuning.NegTTLTimeout, ctx.tuning.NegTTLTemporary, ctx.tuning.NegTTLOther, &ctx.domainCache, ctx.cacheSourceForHost, logf, ) fresh := planning.Fresh cacheNegativeHits := planning.CacheNegativeHits quarantineHits := planning.QuarantineHits staleHits := planning.StaleHits precheckScheduled := planning.PrecheckScheduled toResolve := planning.ToResolve resolved := map[string][]string{} for k, v := range fresh { resolved[k] = v } toResolveTotal := len(toResolve) liveP1 := 0 liveP2 := 0 liveP3 := 0 liveNXHeavyTotal := 0 liveNXHeavySkip := 0 toResolve, liveP1, liveP2, liveP3, liveNXHeavyTotal, liveNXHeavySkip = pickAdaptiveLiveBatch( toResolve, ctx.tuning.LiveBatchTarget, ctx.now, ctx.tuning.LiveBatchNXHeavyPct, ctx.domainCache, ctx.cacheSourceForHost, ctx.wildcards, ) liveDeferred := toResolveTotal - len(toResolve) if liveDeferred < 0 { liveDeferred = 0 } if logf != nil { logf("resolve: domains=%d cache_hits=%d cache_neg_hits=%d quarantine_hits=%d stale_hits=%d precheck_due=%t precheck_scheduled=%d to_resolve=%d to_resolve_total=%d deferred_by_live_batch=%d live_p1=%d live_p2=%d live_p3=%d live_nxheavy_total=%d live_nxheavy_skip=%d", len(ctx.domains), len(fresh), cacheNegativeHits, quarantineHits, staleHits, ctx.tuning.PrecheckDue, precheckScheduled, len(toResolve), toResolveTotal, liveDeferred, liveP1, liveP2, liveP3, liveNXHeavyTotal, liveNXHeavySkip) } resolveBatch := executeResolverBatch( toResolve, ctx.tuning.Workers, ctx.now, ctx.tuning.StaleKeepSec, resolved, &ctx.domainCache, ctx.cacheSourceForHost, func(host string) ([]string, dnsMetrics) { return resolveHostGo(host, ctx.cfg, ctx.metaSpecial, ctx.wildcards, ctx.tuning.DNSTimeout, ctx.cooldown, logf) }, logf, ) dnsStats := resolveBatch.DNSStats resolvedNowDNS := resolveBatch.ResolvedNowDNS resolvedNowStale := resolveBatch.ResolvedNowStale unresolvedAfterAttempts := resolveBatch.UnresolvedAfterAttempts staleHits += resolveBatch.StaleHitsDelta staticEntries, staticSkipped := parseStaticEntriesGo(ctx.staticLines, logf) staticLabels, ptrLookups, ptrErrors := resolveStaticLabels(staticEntries, ctx.cfg, ctx.ptrCache, ctx.tuning.TTL, logf) isWildcardHost := func(host string) bool { switch ctx.cfg.Mode { case DNSModeSmartDNS: return true case DNSModeHybridWildcard: return ctx.wildcards.Match(host) default: return false } } artifacts := buildResolverArtifacts(resolved, staticLabels, isWildcardHost) res.IPMap = artifacts.IPMap res.DirectIPMap = artifacts.DirectIPMap res.WildcardIPMap = artifacts.WildcardIPMap res.IPs = artifacts.IPs res.DirectIPs = artifacts.DirectIPs res.WildcardIPs = artifacts.WildcardIPs res.DomainCache = ctx.domainCache.toMap() res.PtrCache = ctx.ptrCache logResolverSummary( resolverSummaryLogInput{ DomainsTotal: len(ctx.domains), FreshCount: len(fresh), CacheNegativeHits: cacheNegativeHits, QuarantineHits: quarantineHits, StaleHits: staleHits, ResolvedTotal: len(resolved), UnresolvedAfterAttempts: unresolvedAfterAttempts, LiveBatchTarget: ctx.tuning.LiveBatchTarget, LiveDeferred: liveDeferred, LiveP1: liveP1, LiveP2: liveP2, LiveP3: liveP3, LiveBatchNXHeavyPct: ctx.tuning.LiveBatchNXHeavyPct, LiveNXHeavyTotal: liveNXHeavyTotal, LiveNXHeavySkip: liveNXHeavySkip, StaticEntries: len(staticEntries), StaticSkipped: staticSkipped, UniqueIPs: len(res.IPs), DirectIPs: len(res.DirectIPs), WildcardIPs: len(res.WildcardIPs), PtrLookups: ptrLookups, PtrErrors: ptrErrors, DNSStats: dnsStats, TimeoutRecheck: ctx.timeoutRecheck, DurationMS: time.Since(start).Milliseconds(), DomainStateSummary: ctx.domainCache.formatStateSummary(ctx.now), ResolvedNowDNS: resolvedNowDNS, ResolvedNowStale: resolvedNowStale, PrecheckDue: ctx.tuning.PrecheckDue, PrecheckScheduled: precheckScheduled, PrecheckStatePath: ctx.precheckStatePath, }, logf, ) _ = finalizeResolverPrecheck( ctx.tuning.PrecheckDue, ctx.precheckStatePath, ctx.now, ctx.timeoutRecheck, ctx.tuning.LiveBatchTarget, ctx.tuning.LiveBatchMin, ctx.tuning.LiveBatchMax, ctx.tuning.LiveBatchNXHeavyPct, ctx.tuning.LiveBatchNXHeavyMin, ctx.tuning.LiveBatchNXHeavyMax, dnsStats, liveDeferred, resolvedNowDNS, liveP1, liveP2, liveP3, liveNXHeavyTotal, liveNXHeavySkip, toResolveTotal, ctx.precheckFileForced, precheckForcePath, logf, ) }