[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated":58,"\u002Fblog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated-surround":471},[4],{"title":5,"path":6,"stem":7,"children":8,"page":57},"Blog","\u002Fblog","blog",[9,13,17,21,25,29,33,37,41,45,49,53],{"title":10,"path":11,"stem":12},"A Guide to Server-Side Rendering (SSR) with Vite and React.js","\u002Fblog\u002Fa-guide-to-server-side-rendering-ssr-with-vite-and-reactjs","blog\u002Fa-guide-to-server-side-rendering-ssr-with-vite-and-reactjs",{"title":14,"path":15,"stem":16},"🔄 Background DNS Refresh in Node.js: Keeping Cached IPs Updated","\u002Fblog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated","blog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated",{"title":18,"path":19,"stem":20},"Comprehensive Guide: Encrypting Images, Uploading to Cloudinary, and Serving Them Securely","\u002Fblog\u002Fcomprehensive-guide-encrypting-images-uploading-to-cloudinary-and-serving-them-securely","blog\u002Fcomprehensive-guide-encrypting-images-uploading-to-cloudinary-and-serving-them-securely",{"title":22,"path":23,"stem":24},"Comprehensive Guide to Using Uploadthing with Express and Typescript","\u002Fblog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript","blog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript",{"title":26,"path":27,"stem":28},"🌐 DNS Caching in Node.js: Supercharge Your App's Speed & Reliability 🚀","\u002Fblog\u002Fdns-caching-in-nodejs-supercharge-your-apps-speed-and-reliability","blog\u002Fdns-caching-in-nodejs-supercharge-your-apps-speed-and-reliability",{"title":30,"path":31,"stem":32},"Enhancing Redis for Message Queues: Using External Databases for Payload Storage","\u002Fblog\u002Fenhancing-redis-for-message-queues-using-external-databases-for-payload-storage","blog\u002Fenhancing-redis-for-message-queues-using-external-databases-for-payload-storage",{"title":34,"path":35,"stem":36},"Full Stack Learning Management System (LMS) with MERN Stack: A Complete Guide","\u002Fblog\u002Ffull-stack-learning-management-system-lms-with-mern-stack-a-complete-guide","blog\u002Ffull-stack-learning-management-system-lms-with-mern-stack-a-complete-guide",{"title":38,"path":39,"stem":40},"Getting Started with Redis: Elevating Your Web Applications","\u002Fblog\u002Fgetting-started-with-redis-elevating-your-web-applications","blog\u002Fgetting-started-with-redis-elevating-your-web-applications",{"title":42,"path":43,"stem":44},"How Queues Enhance Your Application Development Process","\u002Fblog\u002Fhow-queues-enhance-your-application-development-process","blog\u002Fhow-queues-enhance-your-application-development-process",{"title":46,"path":47,"stem":48},"Next-Gen E-Learning: Transforming Education for Students and Creators","\u002Fblog\u002Fnext-gen-e-learning-transforming-education-for-students-and-creators","blog\u002Fnext-gen-e-learning-transforming-education-for-students-and-creators",{"title":50,"path":51,"stem":52},"Single Sign-On (SSO) Implementation Using Passport.js in TypeScript","\u002Fblog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript","blog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript",{"title":54,"path":55,"stem":56},"Using Multer for Local File Uploads: Benefits, Trade-offs, and Cloud Transfer Integration","\u002Fblog\u002Fusing-multer-for-local-file-uploads-benefits-trade-offs-and-cloud-transfer-integration","blog\u002Fusing-multer-for-local-file-uploads-benefits-trade-offs-and-cloud-transfer-integration",false,{"id":59,"title":14,"author":60,"body":66,"date":463,"description":464,"extension":465,"image":466,"meta":467,"minRead":446,"navigation":468,"path":15,"seo":469,"stem":16,"__hash__":470},"blog\u002Fblog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated.md",{"name":61,"to":62,"username":63,"avatar":64},"Sachin Thapa","https:\u002F\u002Fsachinthapa.hashnode.dev\u002F","sachinthapa572",{"src":65,"alt":61},"https:\u002F\u002Fcdn.hashnode.com\u002Fres\u002Fhashnode\u002Fimage\u002Fupload\u002Fv1733546636355\u002Fa4ae8ce5-eb4c-4ed8-ab9d-15a4b8f32ea5.png?w=500&h=500&fit=crop&crop=entropy&auto=compress,format&format=webp",{"type":67,"value":68,"toc":439},"minimark",[69,74,86,89,92,111,114,118,123,126,141,145,153,160,167,174,178,181,185,188,205,209,216,222,228,234,238,242,253,257,263,267,273,277,364,368,400,404,407,411,425,429,432],[70,71,73],"h2",{"id":72},"introduction","📌 Introduction",[75,76,77,78,85],"p",{},"In our previous blog on ",[79,80,84],"a",{"href":81,"rel":82},"https:\u002F\u002Fsachinthapa.hashnode.dev\u002Fdns-caching-in-nodejs-why-and-how-to-optimize-api-performance",[83],"nofollow","DNS Caching in Node.js",", we learned how caching resolved IP addresses improves performance and prevents frequent DNS lookups. However, one challenge remains: what happens when the TTL expires?",[75,87,88],{},"With basic DNS caching, when an IP address expires, our system performs a fresh DNS lookup before serving the next request. This creates latency spikes and blocking operations for users. To fix this problem, we need to implement background DNS refresh.",[75,90,91],{},"In this comprehensive guide, we'll cover:",[93,94,95,99,102,105,108],"ul",{},[96,97,98],"li",{},"Why background DNS refresh is essential for consistent performance",[96,100,101],{},"How it eliminates latency spikes in high-traffic applications",[96,103,104],{},"A detailed implementation in Node.js with scheduled updates",[96,106,107],{},"Performance benchmarks comparing on-demand and background refresh",[96,109,110],{},"Best practices for production environments",[75,112,113],{},"By the end, you'll know how to keep cached DNS records fresh without ever blocking requests! 🚀",[70,115,117],{"id":116},"the-problem-delayed-dns-refresh-causes-latency-spikes","❌ The Problem: Delayed DNS Refresh Causes Latency Spikes",[119,120,122],"h3",{"id":121},"how-basic-dns-caching-works","🔹 How Basic DNS Caching Works",[75,124,125],{},"With the basic caching approach:",[127,128,129,132,135,138],"ol",{},[96,130,131],{},"We resolve a domain name to an IP and cache it until the TTL expires",[96,133,134],{},"After TTL expiration, the next request triggers a fresh DNS lookup",[96,136,137],{},"That specific request experiences a delay while waiting for DNS resolution",[96,139,140],{},"Subsequent requests are fast again until the next expiration",[119,142,144],{"id":143},"issues-with-this-approach","🔹 Issues with This Approach",[75,146,147,148,152],{},"1️⃣ ",[149,150,151],"strong",{},"Latency Spikes"," – Users experience periodic delays when an expired cache is refreshed",[75,154,155,156,159],{},"2️⃣ ",[149,157,158],{},"Blocking Requests"," – The first request after expiration waits for a DNS resolution",[75,161,162,163,166],{},"3️⃣ ",[149,164,165],{},"Inconsistent Performance"," – Some requests are fast (cached IPs), others are slow (DNS lookups)",[75,168,169,170,173],{},"4️⃣ ",[149,171,172],{},"Poor User Experience"," – Unpredictable response times frustrate users",[70,175,177],{"id":176},"solution-refresh-ips-in-the-background","📌 Solution: Refresh IPs in the Background",[75,179,180],{},"Instead of waiting for a request to trigger a DNS resolution, we can refresh cached IPs proactively before they expire. This ensures continuous smooth operation without any request ever having to wait.",[70,182,184],{"id":183},"the-solution-implementing-background-dns-refresh","✅ The Solution: Implementing Background DNS Refresh",[75,186,187],{},"Our improved approach:",[127,189,190,193,196,199,202],{},[96,191,192],{},"Resolve and cache DNS records as before",[96,194,195],{},"Calculate when to refresh (typically at 80% of TTL)",[96,197,198],{},"Schedule background refresh tasks before TTL expiry",[96,200,201],{},"Keep cached records updated without impacting incoming requests",[96,203,204],{},"Ensure consistent performance for all users",[119,206,208],{"id":207},"benefits-of-background-dns-refresh","🔥 Benefits of Background DNS Refresh:",[75,210,211,212,215],{},"✅ ",[149,213,214],{},"Eliminates latency spikes"," – Requests never wait for DNS lookups",[75,217,211,218,221],{},[149,219,220],{},"Prevents blocking requests"," – Cached IPs are always ready before expiration",[75,223,211,224,227],{},[149,225,226],{},"Smoothens API performance"," – Provides consistent, predictable response times",[75,229,211,230,233],{},[149,231,232],{},"Handles DNS failures gracefully"," – If a refresh fails, the existing IP remains valid",[70,235,237],{"id":236},"implementation-background-dns-refresh-in-nodejs","🔧 Implementation: Background DNS Refresh in Node.js",[119,239,241],{"id":240},"step-1-enhance-the-cache-to-support-background-refresh","Step 1: Enhance the Cache to Support Background Refresh",[243,244,249],"pre",{"className":245,"code":247,"language":248},[246],"language-text","import express from \"express\";\nimport fetch from \"node-fetch\";\nimport * as dns from \"node:dns\";\n\nconst app = express();\nconst PORT = 3000;\nconst dnsCache = new Map();\nconst REFRESH_THRESHOLD = 0.8; \u002F\u002F Refresh when 80% of TTL has elapsed\n\nasync function resolveAndCache(domain) {\n    try {\n        const result = await dns.promises.resolve4(domain, { ttl: true });\n        if (result.length > 0) {\n            const { address, ttl } = result[0];\n            const now = Date.now();\n            const expiresAt = now + ttl * 1000;\n\n            \u002F\u002F Calculate when to refresh (before expiry)\n            const refreshAt = now + (ttl * REFRESH_THRESHOLD * 1000);\n\n            \u002F\u002F Store both expiry and refresh times\n            dnsCache.set(domain, { \n                address, \n                expiresAt,\n                refreshAt\n            });\n\n            console.log(`Updated IP for ${domain}: ${address} (TTL: ${ttl}s)`);\n\n            \u002F\u002F Schedule background refresh before expiry\n            const timeUntilRefresh = refreshAt - now;\n            setTimeout(() => refreshDomain(domain), timeUntilRefresh);\n\n            return address;\n        }\n    } catch (error) {\n        console.error(`DNS lookup failed for ${domain}:`, error);\n    }\n    return null;\n}\n","text",[250,251,247],"code",{"__ignoreMap":252},"",[119,254,256],{"id":255},"step-2-set-up-a-background-refresh-process","Step 2: Set Up a Background Refresh Process",[243,258,261],{"className":259,"code":260,"language":248},[246],"async function refreshDomain(domain) {\n    console.log(`Background refresh for ${domain}`);\n    const cached = dnsCache.get(domain);\n\n    \u002F\u002F Only refresh if this entry still exists and hasn't been refreshed already\n    if (cached && Date.now() \u003C cached.expiresAt && Date.now() >= cached.refreshAt) {\n        await resolveAndCache(domain);\n    }\n}\n\n\u002F\u002F Function to get a cached IP (with fallback to resolution)\nasync function getCachedIP(domain) {\n    const now = Date.now();\n\n    \u002F\u002F Check if domain is cached and still valid\n    if (dnsCache.has(domain)) {\n        const { address, expiresAt } = dnsCache.get(domain);\n        if (now \u003C expiresAt) {\n            return address;\n        }\n    }\n\n    \u002F\u002F Not cached or expired, resolve now\n    return await resolveAndCache(domain);\n}\n\n\u002F\u002F Initialize cache for commonly used domains\nasync function initializeCache(domains) {\n    for (const domain of domains) {\n        await resolveAndCache(domain);\n    }\n}\n\nconst monitoredDomains = [\"api.weather.com\", \"api.payments.com\", \"api.auth.com\"];\ninitializeCache(monitoredDomains);\n",[250,262,260],{"__ignoreMap":252},[119,264,266],{"id":265},"step-3-use-cached-ips-without-delays","Step 3: Use Cached IPs Without Delays",[243,268,271],{"className":269,"code":270,"language":248},[246],"app.get(\"\u002Fweather\", async (req, res) => {\n    const weatherAPI = \"api.weather.com\";\n    try {\n        const ip = await getCachedIP(weatherAPI);\n        if (!ip) return res.status(500).json({ error: \"DNS lookup failed\" });\n\n        const response = await fetch(`http:\u002F\u002F${ip}\u002Fdata`, {\n            headers: { 'Host': 'api.weather.com' }\n        });\n\n        const data = await response.json();\n        res.json({ success: true, data });\n    } catch (error) {\n        res.status(500).json({ error: \"Failed to fetch weather data\" });\n    }\n});\n\napp.listen(PORT, () => console.log(`Server running on port ${PORT}`));\n",[250,272,270],{"__ignoreMap":252},[70,274,276],{"id":275},"performance-comparison-with-vs-without-background-refresh","⚡ Performance Comparison: With vs. Without Background Refresh",[278,279,280,296],"table",{},[281,282,283],"thead",{},[284,285,286,290,293],"tr",{},[287,288,289],"th",{},"Feature",[287,291,292],{},"Without Background Refresh",[287,294,295],{},"With Background Refresh",[297,298,299,310,320,331,342,353],"tbody",{},[284,300,301,304,307],{},[302,303,151],"td",{},[302,305,306],{},"Present (after TTL expiry)",[302,308,309],{},"Eliminated completely",[284,311,312,314,317],{},[302,313,158],{},[302,315,316],{},"First request after expiry is slow",[302,318,319],{},"No blocking requests ever",[284,321,322,325,328],{},[302,323,324],{},"DNS Lookup Frequency",[302,326,327],{},"On-demand (delayed)",[302,329,330],{},"Periodic (proactive)",[284,332,333,336,339],{},[302,334,335],{},"Performance",[302,337,338],{},"Inconsistent",[302,340,341],{},"Smooth & consistent",[284,343,344,347,350],{},[302,345,346],{},"p95 Latency",[302,348,349],{},"150-250ms",[302,351,352],{},"5-10ms",[284,354,355,358,361],{},[302,356,357],{},"p99 Latency",[302,359,360],{},"300-400ms",[302,362,363],{},"10-15ms",[70,365,367],{"id":366},"best-practices-for-production","🎯 Best Practices for Production",[127,369,370,376,382,388,394],{},[96,371,372,375],{},[149,373,374],{},"Adjust the refresh threshold"," based on your application's needs (80% of TTL is a good starting point)",[96,377,378,381],{},[149,379,380],{},"Monitor DNS resolution times"," to identify performance issues",[96,383,384,387],{},[149,385,386],{},"Implement error handling"," in refresh operations to avoid crashing the application",[96,389,390,393],{},[149,391,392],{},"Consider memory usage"," when caching many domains",[96,395,396,399],{},[149,397,398],{},"Use health checks"," to ensure your background refresh process is working properly",[70,401,403],{"id":402},"final-thoughts","🚀 Final Thoughts",[75,405,406],{},"✅ Background DNS refresh ensures that DNS lookups never block a request, eliminating latency spikes and providing consistent performance.",[119,408,410],{"id":409},"ideal-use-cases","💡 Ideal Use Cases:",[93,412,413,416,419,422],{},[96,414,415],{},"APIs handling thousands of requests per second",[96,417,418],{},"Microservices communicating with third-party services",[96,420,421],{},"IoT devices that need uninterrupted connectivity",[96,423,424],{},"Payment gateways, streaming services, and real-time applications",[119,426,428],{"id":427},"next-steps","🔥 Next Steps",[75,430,431],{},"In our next blog post, we'll explore how to implement a robust DNS fallback mechanism that can handle DNS resolution failures gracefully, ensuring your application stays operational even when DNS providers experience issues.",[75,433,434,435,438],{},"Check out our previous blog on ",[79,436,84],{"href":81,"rel":437},[83]," and stay tuned for our upcoming post on DNS Fallback Mechanisms! 🚀",{"title":252,"searchDepth":440,"depth":440,"links":441},2,[442,443,448,449,452,457,458,459],{"id":72,"depth":440,"text":73},{"id":116,"depth":440,"text":117,"children":444},[445,447],{"id":121,"depth":446,"text":122},3,{"id":143,"depth":446,"text":144},{"id":176,"depth":440,"text":177},{"id":183,"depth":440,"text":184,"children":450},[451],{"id":207,"depth":446,"text":208},{"id":236,"depth":440,"text":237,"children":453},[454,455,456],{"id":240,"depth":446,"text":241},{"id":255,"depth":446,"text":256},{"id":265,"depth":446,"text":266},{"id":275,"depth":440,"text":276},{"id":366,"depth":440,"text":367},{"id":402,"depth":440,"text":403,"children":460},[461,462],{"id":409,"depth":446,"text":410},{"id":427,"depth":446,"text":428},"2025-03-11","Learn how to implement background DNS refresh in Node.js to maintain consistent performance and eliminate latency spikes in high-traffic applications","md","\u002Fimages\u002Fblog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated.png",{},true,{"title":14,"description":464},"o60gjFJTCvrXQkO1HOjDfxkAbQsN2sJmRQS6xjaHJ08",[472,474],{"title":10,"path":11,"stem":12,"description":473,"children":-1},"Learn to implement Server-Side Rendering (SSR) with React.js and Vite for improved web performance and SEO",{"title":18,"path":19,"stem":20,"description":475,"children":-1},"Learn to encrypt images, upload securely to Cloudinary, and serve them safely with this comprehensive guide on secure image handling processes"]