IO proxy: client-side cache with 5min TTL, server Cache-Control
Client caches IO results by (name + args) in memory. In-flight promises are cached too (dedup concurrent calls for same args). Server adds Cache-Control: public, max-age=300 for HTTP caching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1698,10 +1698,24 @@ ASYNC_IO_JS = '''
|
||||
return asyncRenderChildren(exprs, env, null);
|
||||
}
|
||||
|
||||
// IO proxy cache: key → { value, expires }
|
||||
var _ioCache = {};
|
||||
var IO_CACHE_TTL = 300000; // 5 minutes
|
||||
|
||||
// Register a server-proxied IO primitive: fetches from /sx/io/<name>
|
||||
// Uses GET for short args, POST for long payloads (URL length safety).
|
||||
// Results are cached client-side by (name + args) with a TTL.
|
||||
function registerProxiedIo(name) {
|
||||
registerIoPrimitive(name, function(args, kwargs) {
|
||||
// Cache key: name + serialized args
|
||||
var cacheKey = name;
|
||||
for (var ci = 0; ci < args.length; ci++) cacheKey += "\0" + String(args[ci]);
|
||||
for (var ck in kwargs) {
|
||||
if (kwargs.hasOwnProperty(ck)) cacheKey += "\0" + ck + "=" + String(kwargs[ck]);
|
||||
}
|
||||
var cached = _ioCache[cacheKey];
|
||||
if (cached && cached.expires > Date.now()) return cached.value;
|
||||
|
||||
var url = "/sx/io/" + encodeURIComponent(name);
|
||||
var qs = [];
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
@@ -1734,7 +1748,7 @@ ASYNC_IO_JS = '''
|
||||
if (queryStr) url += "?" + queryStr;
|
||||
fetchOpts = { headers: { "SX-Request": "true" } };
|
||||
}
|
||||
return fetch(url, fetchOpts)
|
||||
var result = fetch(url, fetchOpts)
|
||||
.then(function(resp) {
|
||||
if (!resp.ok) {
|
||||
logWarn("sx:io " + name + " failed " + resp.status);
|
||||
@@ -1746,7 +1760,9 @@ ASYNC_IO_JS = '''
|
||||
if (!text || text === "nil") return NIL;
|
||||
try {
|
||||
var exprs = parse(text);
|
||||
return exprs.length === 1 ? exprs[0] : exprs;
|
||||
var val = exprs.length === 1 ? exprs[0] : exprs;
|
||||
_ioCache[cacheKey] = { value: val, expires: Date.now() + IO_CACHE_TTL };
|
||||
return val;
|
||||
} catch (e) {
|
||||
logWarn("sx:io " + name + " parse error: " + (e && e.message ? e.message : e));
|
||||
return NIL;
|
||||
@@ -1756,6 +1772,9 @@ ASYNC_IO_JS = '''
|
||||
logWarn("sx:io " + name + " network error: " + (e && e.message ? e.message : e));
|
||||
return NIL;
|
||||
});
|
||||
// Cache the in-flight promise too (dedup concurrent calls for same args)
|
||||
_ioCache[cacheKey] = { value: result, expires: Date.now() + IO_CACHE_TTL };
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user