Skip to content

Commit 1a98cda

Browse files
authored
fix: ensure conditional upstreams initialize independently of default upstreams (#1890)
Fixes #1639 where conditional DNS mappings would fail with "Not Ready" errors when the default upstream was unreachable, even though conditional upstreams have their own independent DNS servers. The issue occurred when using `upstreams.init.strategy: fast`, where conditional upstreams inherited the async initialization behavior. If default upstreams were unreachable during this initialization window, ALL queries (including conditional ones) would fail. Changes: - Conditional upstreams now always use blocking initialization regardless of the global init strategy - This ensures conditional DNS mappings are fully ready before accepting queries and can resolve independently of default upstream status - Updated test expectations to reflect the new resilient behavior Impact: Users with conditional DNS mappings (e.g., `local.dev: 192.168.1.1`) will now have reliable local DNS resolution even when their primary internet upstreams are down or unreachable.
1 parent 9e293c0 commit 1a98cda

File tree

2 files changed

+14
-5
lines changed

2 files changed

+14
-5
lines changed

resolver/conditional_upstream_resolver.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@ func NewConditionalUpstreamResolver(
3030

3131
for domain, upstreams := range cfg.Mapping.Upstreams {
3232
name := fmt.Sprintf("<conditional in %s>", domain)
33-
cfg := config.NewUpstreamGroup(name, upstreamsCfg, upstreams)
33+
groupCfg := config.NewUpstreamGroup(name, upstreamsCfg, upstreams)
3434

35-
r, err := NewParallelBestResolver(ctx, cfg, bootstrap)
35+
// Override init strategy for conditional upstreams to always use blocking initialization.
36+
// This ensures conditional upstreams are always ready to resolve their domains,
37+
// even if the default upstream is unreachable during async initialization.
38+
// See: https://github.com/0xERR0R/blocky/issues/1639
39+
groupCfg.Init.Strategy = config.InitStrategyBlocking
40+
41+
r, err := NewParallelBestResolver(ctx, groupCfg, bootstrap)
3642
if err != nil {
3743
return nil, err
3844
}

resolver/conditional_upstream_resolver_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ var _ = Describe("ConditionalUpstreamResolver", Label("conditionalResolver"), fu
193193
})
194194

195195
When("upstream is invalid", func() {
196-
It("errors during construction", func() {
196+
It("succeeds with bootstrap resolver during construction", func() {
197197
b := newTestBootstrap(ctx, &dns.Msg{MsgHdr: dns.MsgHdr{Rcode: dns.RcodeServerFailure}})
198198

199199
upstreamsCfg := defaultUpstreamsConfig
@@ -207,9 +207,12 @@ var _ = Describe("ConditionalUpstreamResolver", Label("conditionalResolver"), fu
207207
},
208208
}
209209

210+
// Conditional upstreams should always succeed during construction to ensure
211+
// they remain available even when default upstreams are unreachable.
212+
// See: https://github.com/0xERR0R/blocky/issues/1639
210213
r, err := NewConditionalUpstreamResolver(ctx, sutConfig, upstreamsCfg, b)
211-
Expect(err).Should(HaveOccurred())
212-
Expect(r).Should(BeNil())
214+
Expect(err).ShouldNot(HaveOccurred())
215+
Expect(r).ShouldNot(BeNil())
213216
})
214217
})
215218

0 commit comments

Comments
 (0)