From 9972ef2f695e9bd3cc0fd604e45cee262514aa81 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 20 Feb 2023 00:22:11 +0100 Subject: [PATCH] refactor: newCachedDNS --- blockstore.go | 4 ++-- blockstore_caboose.go | 6 +++--- dns_cache.go | 42 ++++++++++++++++++++++++++++-------------- handlers.go | 8 ++++---- main.go | 5 ++++- 5 files changed, 41 insertions(+), 24 deletions(-) diff --git a/blockstore.go b/blockstore.go index 79f02d5..b386e5f 100644 --- a/blockstore.go +++ b/blockstore.go @@ -13,8 +13,8 @@ import ( const GetBlockTimeout = time.Second * 60 -func newExchange(orchestrator, loggingEndpoint string) (exchange.Interface, error) { - b, err := newCabooseBlockStore(orchestrator, loggingEndpoint) +func newExchange(orchestrator, loggingEndpoint string, cdns *cachedDNS) (exchange.Interface, error) { + b, err := newCabooseBlockStore(orchestrator, loggingEndpoint, cdns) if err != nil { return nil, err } diff --git a/blockstore_caboose.go b/blockstore_caboose.go index 690e552..a6e68ce 100644 --- a/blockstore_caboose.go +++ b/blockstore_caboose.go @@ -10,7 +10,7 @@ import ( blockstore "github.com/ipfs/go-ipfs-blockstore" ) -func newCabooseBlockStore(orchestrator, loggingEndpoint string) (blockstore.Blockstore, error) { +func newCabooseBlockStore(orchestrator, loggingEndpoint string, cdns *cachedDNS) (blockstore.Blockstore, error) { var ( orchURL *url.URL loggURL *url.URL @@ -35,7 +35,7 @@ func newCabooseBlockStore(orchestrator, loggingEndpoint string) (blockstore.Bloc Timeout: caboose.DefaultSaturnRequestTimeout, Transport: &withUserAgent{ RoundTripper: &http.Transport{ - DialContext: dialWithCachedDNS, + DialContext: cdns.dialWithCachedDNS, }, }, } @@ -50,7 +50,7 @@ func newCabooseBlockStore(orchestrator, loggingEndpoint string) (blockstore.Bloc MaxIdleConnsPerHost: 100, IdleConnTimeout: 90 * time.Second, - DialContext: dialWithCachedDNS, + DialContext: cdns.dialWithCachedDNS, // Saturn Weltschmerz TLSClientConfig: &tls.Config{ diff --git a/dns_cache.go b/dns_cache.go index 1b3e113..24f4e45 100644 --- a/dns_cache.go +++ b/dns_cache.go @@ -8,37 +8,46 @@ import ( "github.com/rs/dnscache" ) -// Local DNS cache because in this world things are ephemeral -var dnsCache = &dnscache.Resolver{} - // How often should we check for successful updates to cached entries const dnsCacheRefreshInterval = 5 * time.Minute -func init() { +// Local DNS cache because in this world things are ephemeral +type cachedDNS struct { + resolver *dnscache.Resolver + refresher *time.Ticker +} + +func newCachedDNS(refreshInterval time.Duration) *cachedDNS { + cache := &cachedDNS{ + resolver: &dnscache.Resolver{}, + refresher: time.NewTicker(refreshInterval), + } + // Configure DNS cache to not remove stale records to protect gateway from // catastrophic failures like https://github.com/ipfs/bifrost-gateway/issues/34 options := dnscache.ResolverRefreshOptions{} options.ClearUnused = false options.PersistOnFailure = true - // Every dnsCacheRefreshInterval we check for updates, but if there is + // Every refreshInterval we check for updates, but if there is // none, or if domain disappears, we keep the last cached version - go func() { - t := time.NewTicker(dnsCacheRefreshInterval) - defer t.Stop() - for range t.C { - dnsCache.RefreshWithOptions(options) + go func(cdns *cachedDNS) { + defer cdns.refresher.Stop() + for range cdns.refresher.C { + cdns.resolver.RefreshWithOptions(options) } - }() + }(cache) + + return cache } -// dialWithCachedDNS implements DialContext that uses dnsCache -func dialWithCachedDNS(ctx context.Context, network string, addr string) (conn net.Conn, err error) { +// dialWithCachedDNS implements DialContext that uses cachedDNS +func (cdns *cachedDNS) dialWithCachedDNS(ctx context.Context, network string, addr string) (conn net.Conn, err error) { host, port, err := net.SplitHostPort(addr) if err != nil { return nil, err } - ips, err := dnsCache.LookupHost(ctx, host) + ips, err := cdns.resolver.LookupHost(ctx, host) if err != nil { return nil, err } @@ -52,3 +61,8 @@ func dialWithCachedDNS(ctx context.Context, network string, addr string) (conn n } return } + +func (cdns *cachedDNS) Close() error { + cdns.refresher.Stop() + return nil +} diff --git a/handlers.go b/handlers.go index 3ab2a9d..7ef2f0c 100644 --- a/handlers.go +++ b/handlers.go @@ -39,14 +39,14 @@ func withRequestLogger(next http.Handler) http.Handler { }) } -func makeGatewayHandler(saturnOrchestrator, saturnLogger string, kuboRPC []string, port int, blockCacheSize int) (*http.Server, error) { +func makeGatewayHandler(saturnOrchestrator, saturnLogger string, kuboRPC []string, port int, blockCacheSize int, cdns *cachedDNS) (*http.Server, error) { // Sets up an exchange based on using Saturn as block storage - exch, err := newExchange(saturnOrchestrator, saturnLogger) + exch, err := newExchange(saturnOrchestrator, saturnLogger, cdns) if err != nil { return nil, err } - // Sets up an LRU cache to store blocks in + // Sets up a cache to store blocks in cacheBlockStore, err := newCacheBlockStore(blockCacheSize) if err != nil { return nil, err @@ -55,7 +55,7 @@ func makeGatewayHandler(saturnOrchestrator, saturnLogger string, kuboRPC []strin // Set up support for identity hashes (https://github.com/ipfs/bifrost-gateway/issues/38) cacheBlockStore = bstore.NewIdStore(cacheBlockStore) - // Sets up a blockservice which tries the LRU cache and falls back to the exchange + // Sets up a blockservice which tries the cache and falls back to the exchange blockService := blockservice.New(cacheBlockStore, exch) // Sets up the routing system, which will proxy the IPNS routing requests to the given gateway. diff --git a/main.go b/main.go index b5b6692..cb986c9 100644 --- a/main.go +++ b/main.go @@ -52,7 +52,10 @@ var rootCmd = &cobra.Command{ log.Printf("Starting %s %s", name, version) - gatewaySrv, err := makeGatewayHandler(saturnOrchestrator, saturnLogger, kuboRPC, gatewayPort, blockCacheSize) + cdns := newCachedDNS(dnsCacheRefreshInterval) + defer cdns.Close() + + gatewaySrv, err := makeGatewayHandler(saturnOrchestrator, saturnLogger, kuboRPC, gatewayPort, blockCacheSize, cdns) if err != nil { return err }