S
Supanote
Sign in Sign up

Memcached Meta Protocol (mg/ms) Anti-Stampede & Stale-While-Revalidate

code (javascript) 1 day ago · 78 lines · 4 views
Verified Blueprint Memcached 1.6.34+

Zero-dependency Node.js client for Memcached 1.6+ Meta Protocol (mg N/W/Z/X flags) preventing cache stampedes with stale-while-revalidate.

  • ✓ Uses modern single-line Meta Get (mg <key> v t N30 R15) replacing the deprecated binary protocol
  • ✓ Handles native W (winner lock) and Z (already-won backoff) flags to stop thundering herd DB spikes
  • ✓ Serves stale values immediately when X/W flags appear while refreshing cache asynchronously in background
Quick Fetch
1'use strict';
2// Zero-Dependency Memcached 1.6+ Meta Protocol Anti-Stampede & SWR Helper (Node.js)
3// Uses native 'mg' flags:
4// v = return value | t = return remaining TTL
5// N30 = auto-vivify stub w/ 30s lease on miss (returns 'W' to ONLY ONE winning caller)
6// R15 = proactive recache if remaining TTL < 15s (winner gets 'W' alongside live value!)
7
8const net = require('node:net');
9
10function sendMetaCommand(socket, line) {
11 return new Promise((resolve, reject) => {
12 let buf = Buffer.alloc(0);
13 const onData = (chunk) => {
14 buf = Buffer.concat([buf, chunk]);
15 const nl = buf.indexOf(0x0d); // '\r\n'
16 if (nl === -1) return;
18 const header = buf.subarray(0, nl).toString('utf8');
19 const parts = header.split(' ');
20 const code = parts[0];
22 if (code === 'VA') {
23 const byteLen = Number(parts[1]);
24 const totalNeeded = nl + 2 + byteLen + 2;
25 if (buf.length < totalNeeded) return;
26 cleanup();
27 const flags = new Set(parts.slice(2));
28 const body = buf.subarray(nl + 2, nl + 2 + byteLen).toString('utf8');
29 resolve({ status: 'VA', flags, body });
30 } else {
31 cleanup();
32 resolve({ status: code, flags: new Set(parts.slice(1)), body: null });
33 }
34 };
35 const onErr = (err) => { cleanup(); reject(err); };
36 const cleanup = () => {
37 socket.off('data', onData);
38 socket.off('error', onErr);
39 };
40 socket.on('data', onData);
41 socket.on('error', onErr);
42 socket.write(line + '\r\n');
43 });
46async function getWithStampedeGuard(socket, key, ttlSec, loaderFn) {
47 // Request value, remaining TTL, 20s miss-lock lease (N20), and early refresh under 15s (R15)
48 const res = await sendMetaCommand(socket, `mg ${key} v t N20 R15`);
49 const wonRecacheLock = res.flags.has('W');
50 const isStaleOrStub = res.flags.has('X') || res.body === '' || res.body === null;
52 // Case 1: Hot hit approaching expiry — serve value immediately & refresh in background
53 if (res.status === 'VA' && !isStaleOrStub) {
54 if (wonRecacheLock) {
55 Promise.resolve(loaderFn()).then((fresh) => {
56 const payload = JSON.stringify(fresh);
57 return sendMetaCommand(socket, `ms ${key} ${Buffer.byteLength(payload)} T${ttlSec}\r\n${payload}`);
58 }).catch(() => {});
59 }
60 return JSON.parse(res.body);
61 }
63 // Case 2: Cache miss where THIS worker won 'W' token — populate cache once for everyone
64 if (wonRecacheLock) {
65 const fresh = await loaderFn();
66 const payload = JSON.stringify(fresh);
67 await sendMetaCommand(socket, `ms ${key} ${Buffer.byteLength(payload)} T${ttlSec}\r\n${payload}`);
68 return fresh;
69 }
71 // Case 3: Concurrent loser received 'Z' token — brief jittered wait then read populated cache
72 await new Promise((r) => setTimeout(r, 35 + Math.floor(Math.random() * 25)));
73 const retry = await sendMetaCommand(socket, `mg ${key} v`);
74 return retry.status === 'VA' && retry.body ? JSON.parse(retry.body) : loaderFn();
77module.exports = { sendMetaCommand, getWithStampedeGuard };

No replies yet

Every reply is a note. Start a discussion, ask a question, or attach a code snippet.

Related Memcached 1.6.34+ & Database, Cache & SQL Blueprints

Production-ready configurations and diagnostics from the verified Supanote library.

All Database, Cache & SQL →
Interactive Developer Workbench: .env, Log & API Key Secret Scanner

Detect and redact leaked AWS keys, JWTs, database URIs, private keys, and Bearer tokens before sharing.

Open Secret Scanner →

Share Note

Open
Download SVG
Social Card Preview
Open on mobile
Point your phone camera to open this note directly

Report this note

Notification