perf: reuse progressive live snapshot during hydration (Closes #1405)
All checks were successful
CI / lint (pull_request) Successful in 3m42s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 6m25s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy 2026-08-25 19:13:23 +00:00
parent 1822004f3d
commit 54cb078d1a
7 changed files with 247 additions and 6 deletions

View File

@ -166,9 +166,47 @@ function createContextPoller({
return refresh({ force: true }); return refresh({ force: true });
} }
function adopt(snapshot) {
if (
stopped || activeRequest || retainedSnapshot || !snapshot ||
typeof snapshot !== 'object' ||
!Object.prototype.hasOwnProperty.call(snapshot, 'context')
) return false;
retainedSnapshot = { ...snapshot };
revisions = { ...(snapshot.revisions || {}) };
failureStreak = 0;
lastSuccessAt = Date.now();
nextDelayMs = snapshotDelay(snapshot);
const changedSections = ['context', 'events', 'notifications'].filter(
section => Object.prototype.hasOwnProperty.call(snapshot, section)
);
onSnapshot(retainedSnapshot, changedSections);
schedule(nextDelayMs);
return true;
}
async function adoptPending(snapshotPromise) {
if (!snapshotPromise || typeof snapshotPromise.then !== 'function') return false;
let deadline = null;
const timeout = new Promise(resolve => {
deadline = setDeadlineTimer(() => resolve(null), timeoutMs);
});
try {
const snapshot = await Promise.race([
Promise.resolve(snapshotPromise).catch(() => null),
timeout,
]);
return adopt(snapshot);
} finally {
clearDeadlineTimer(deadline);
}
}
return { return {
start: refresh, start: refresh,
refresh, refresh,
adopt,
adoptPending,
setVisible, setVisible,
getState() { getState() {
return { return {

View File

@ -8441,9 +8441,12 @@
if (!deviceSetup) await (await ensureDeviceSetup()).open(event); if (!deviceSetup) await (await ensureDeviceSetup()).open(event);
}); });
pushControllerReady.then(ensureDeviceSetup).catch(console.warn); pushControllerReady.then(ensureDeviceSetup).catch(console.warn);
await load(); let adoptedProgressiveSnapshot = contextPoller.adopt(progressiveWorkHandoff?.liveSnapshot);
if (!adoptedProgressiveSnapshot && progressiveWorkHandoff?.liveSnapshotPromise) {
adoptedProgressiveSnapshot = await contextPoller.adoptPending(progressiveWorkHandoff.liveSnapshotPromise);
}
if (!adoptedProgressiveSnapshot) await load();
await appShortcut.run(); await appShortcut.run();
contextPoller.start();
document.addEventListener('visibilitychange', () => { document.addEventListener('visibilitychange', () => {
contextPoller.setVisible(!document.hidden); contextPoller.setVisible(!document.hidden);
if (!document.hidden) deviceSetup?.render(); if (!document.hidden) deviceSetup?.render();

View File

@ -7,6 +7,8 @@ function createProgressiveMyWork({ document, fetchSnapshot }) {
let active = 'all'; let active = 'all';
let stopped = false; let stopped = false;
let selectedByUser = false; let selectedByUser = false;
let liveSnapshot = null;
let liveSnapshotPromise = null;
const deferredQueues = { const deferredQueues = {
today:'Today', agenda:'Agenda', later:'Later', draft:'Drafts', today:'Today', agenda:'Agenda', later:'Later', draft:'Drafts',
}; };
@ -59,13 +61,31 @@ function createProgressiveMyWork({ document, fetchSnapshot }) {
return { return {
handoff() { handoff() {
return { selectedFilter:selectedByUser ? active : null }; const state = { selectedFilter:selectedByUser ? active : null };
if (liveSnapshot) {
state.liveSnapshot = liveSnapshot;
liveSnapshot = null;
liveSnapshotPromise = null;
} else if (liveSnapshotPromise) {
state.liveSnapshotPromise = liveSnapshotPromise;
liveSnapshotPromise = null;
}
return state;
}, },
async start() { async start() {
if (status) status.textContent = 'Loading assigned work…'; if (status) status.textContent = 'Loading assigned work…';
const request = Promise.resolve().then(() => fetchSnapshot());
liveSnapshotPromise = request.then(snapshot => (
snapshot && typeof snapshot === 'object' &&
Object.prototype.hasOwnProperty.call(snapshot, 'context') ? snapshot : null
), () => null);
try { try {
const snapshot = await fetchSnapshot(); const snapshot = await request;
if (stopped) return false; if (stopped) return false;
const transferable = snapshot && typeof snapshot === 'object' &&
Object.prototype.hasOwnProperty.call(snapshot, 'context');
if (transferable) liveSnapshot = snapshot;
else liveSnapshotPromise = null;
const context = snapshot?.context || snapshot || {}; const context = snapshot?.context || snapshot || {};
items = buildMyWork({ ...context, notifications:snapshot?.notifications || context.notifications || [] }); items = buildMyWork({ ...context, notifications:snapshot?.notifications || context.notifications || [] });
updateCounts(); updateCounts();

View File

@ -186,6 +186,7 @@ def test_release_artifact_bootstraps_mobile_home_and_returns_from_insights(
page.goto(origin + "/", wait_until="networkidle") page.goto(origin + "/", wait_until="networkidle")
page.locator('input[name="device_label"]').fill("Home bootstrap release phone") page.locator('input[name="device_label"]').fill("Home bootstrap release phone")
page.locator('input[name="access_token"]').fill(ACCESS_TOKEN) page.locator('input[name="access_token"]').fill(ACCESS_TOKEN)
live_requests.clear()
page.locator("#submit-sign-in").click() page.locator("#submit-sign-in").click()
page.wait_for_url(origin + "/", wait_until="networkidle") page.wait_for_url(origin + "/", wait_until="networkidle")
assert launch_transfer_events.index("workspace-requested") < ( assert launch_transfer_events.index("workspace-requested") < (
@ -193,6 +194,8 @@ def test_release_artifact_bootstraps_mobile_home_and_returns_from_insights(
), launch_transfer_events ), launch_transfer_events
expect(page.locator("#my-work-status")).to_contain_text("2") expect(page.locator("#my-work-status")).to_contain_text("2")
revisionless_live_requests = [url for url in live_requests if "?" not in url]
assert len(revisionless_live_requests) == 1, live_requests
initial_live_requests = len(live_requests) initial_live_requests = len(live_requests)
page.evaluate( page.evaluate(
""" """

View File

@ -117,6 +117,91 @@ const poller = createContextPoller({{
} }
def test_context_poller_adopts_progressive_snapshot_before_revision_conditional_refresh():
script = f"""
const createContextPoller = require({json.dumps(str(POLLER))});
const requested = [];
const rendered = [];
const timers = [];
const seed = {{
context:{{user:{{login:'timmy'}}}}, events:[{{id:7}}], notifications:[],
revisions:{{context:'0123456789abcdef.1',events:'fedcba9876543210.2',notifications:'0011223344556677.3'}},
freshness:{{fresh_for_seconds:8,sections:{{
context:{{degraded:false,age_seconds:2}},events:{{degraded:false,age_seconds:5}},notifications:{{degraded:false,age_seconds:1}},
}}}},
}};
const poller = createContextPoller({{
fetchContext: revisions => {{
requested.push({{...revisions}});
return Promise.resolve({{revisions:{{...revisions}},freshness:seed.freshness}});
}},
onSnapshot: (snapshot, changed) => rendered.push({{login:snapshot.context.user.login,changed}}),
onError: error => {{ throw error; }},
setTimer: (callback, delay) => {{ const timer={{callback,delay}}; timers.push(timer); return timer; }},
clearTimer: () => {{}},
intervalMs:8000,
}});
(async()=>{{
const adopted=poller.adopt(seed);
const before={{adopted,requests:requested.length,rendered:[...rendered],delay:timers[0].delay}};
timers[0].callback();
await new Promise(resolve=>setImmediate(resolve));
process.stdout.write(JSON.stringify({{before,requested}}));
}})();
"""
assert run_node(script) == {
"before": {
"adopted": True,
"requests": 0,
"rendered": [{
"login": "timmy",
"changed": ["context", "events", "notifications"],
}],
"delay": 3000,
},
"requested": [{
"context": "0123456789abcdef.1",
"events": "fedcba9876543210.2",
"notifications": "0011223344556677.3",
}],
}
def test_context_poller_adopts_inflight_progressive_snapshot_without_fetching():
script = f"""
const createContextPoller = require({json.dumps(str(POLLER))});
let calls=0; const rendered=[]; const timers=[];
const snapshot={{context:{{user:{{login:'timmy'}}}},events:[],notifications:[]}};
const poller=createContextPoller({{
fetchContext:()=>{{calls+=1;return Promise.resolve(snapshot);}},
onSnapshot:value=>rendered.push(value.context.user.login),
onError:error=>{{throw error;}},
setTimer:(callback,delay)=>{{const timer={{callback,delay}};timers.push(timer);return timer;}},
clearTimer:()=>{{}}, setDeadlineTimer:()=>1, clearDeadlineTimer:()=>{{}}, intervalMs:8000,
}});
(async()=>{{
const adopted=await poller.adoptPending(Promise.resolve(snapshot));
process.stdout.write(JSON.stringify({{adopted,calls,rendered,delay:timers[0].delay}}));
}})();
"""
assert run_node(script) == {
"adopted": True,
"calls": 0,
"rendered": ["timmy"],
"delay": 8000,
}
def test_dashboard_adopts_progressive_snapshot_or_falls_back_to_immediate_load():
source = DASHBOARD.read_text()
assert "let adoptedProgressiveSnapshot = contextPoller.adopt(progressiveWorkHandoff?.liveSnapshot);" in source
assert "contextPoller.adoptPending(progressiveWorkHandoff.liveSnapshotPromise)" in source
assert "if (!adoptedProgressiveSnapshot) await load();" in source
def test_context_poller_waits_for_server_cooldown_when_every_section_is_degraded(): def test_context_poller_waits_for_server_cooldown_when_every_section_is_degraded():
script = f""" script = f"""
const createContextPoller = require({json.dumps(str(POLLER))}); const createContextPoller = require({json.dumps(str(POLLER))});

View File

@ -96,7 +96,13 @@ async def test_mobile_launch_progressively_discloses_secondary_controls():
assert "BASE + 'static/mobile-app-shortcuts.js'" in service_worker assert "BASE + 'static/mobile-app-shortcuts.js'" in service_worker
bootstrap = (Path(__file__).resolve().parents[1] / "frontend" / "dashboard.js").read_text() bootstrap = (Path(__file__).resolve().parents[1] / "frontend" / "dashboard.js").read_text()
assert "mobileAppShortcuts.createController" in bootstrap assert "mobileAppShortcuts.createController" in bootstrap
assert bootstrap.index("await load();\n await appShortcut.run();") < bootstrap.index("contextPoller.start();") adopted = bootstrap.index(
"let adoptedProgressiveSnapshot = contextPoller.adopt(progressiveWorkHandoff?.liveSnapshot);"
)
fallback = bootstrap.index("if (!adoptedProgressiveSnapshot) await load();")
shortcuts = bootstrap.index("await appShortcut.run();")
assert adopted < fallback < shortcuts
assert "contextPoller.start();" not in bootstrap
assert "mobileLaunch.chooseFilter" in html assert "mobileLaunch.chooseFilter" in html
assert "agenda: counts.agenda" in html assert "agenda: counts.agenda" in html
assert "mobileLaunch.createDisclosure" in html assert "mobileLaunch.createDisclosure" in html

View File

@ -133,4 +133,90 @@ const flow=context.module.exports({{document,fetchSnapshot:async()=>({{user:{{lo
dashboard = DASHBOARD.read_text() dashboard = DASHBOARD.read_text()
assert "const progressiveWorkHandoff = window.stackchainProgressiveMyWork?.handoff?.();" in dashboard assert "const progressiveWorkHandoff = window.stackchainProgressiveMyWork?.handoff?.();" in dashboard
assert "progressiveWorkHandoff?.selectedFilter" in dashboard assert "progressiveWorkHandoff?.selectedFilter" in dashboard
def test_progressive_live_snapshot_is_handed_to_the_workspace_exactly_once():
harness = f"""
const fs=require('fs'); const vm=require('vm');
const document={{
querySelector:selector=>selector==='#my-work-list'?{{innerHTML:''}}:selector==='#my-work-status'?{{textContent:''}}:null,
querySelectorAll:()=>[],
}};
const context={{module:{{exports:{{}}}},exports:{{}},console,URL,document}}; vm.createContext(context);
vm.runInContext(fs.readFileSync({json.dumps(str(MY_WORK))},'utf8'),context);
context.buildMyWork=context.module.exports; context.module={{exports:{{}}}};
vm.runInContext(fs.readFileSync({json.dumps(str(MODULE))},'utf8'),context);
const snapshot={{
context:{{user:{{login:'timmy'}},issues:[],pull_requests:[]}},
events:[{{id:7}}], notifications:[],
revisions:{{context:'0123456789abcdef.1',events:'fedcba9876543210.2',notifications:'0011223344556677.3'}},
freshness:{{fresh_for_seconds:8,sections:{{
context:{{degraded:false,age_seconds:2}},events:{{degraded:false,age_seconds:2}},notifications:{{degraded:false,age_seconds:2}},
}}}},
}};
const flow=context.module.exports({{document,fetchSnapshot:async()=>snapshot}});
(async()=>{{
await flow.start();
const first=flow.handoff(); const second=flow.handoff();
console.log(JSON.stringify({{
firstSnapshot:first.liveSnapshot,
secondHasSnapshot:Object.prototype.hasOwnProperty.call(second,'liveSnapshot'),
}}));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
result = subprocess.run(["node", "-e", harness], check=True, capture_output=True, text=True)
state = json.loads(result.stdout)
assert state == {"firstSnapshot": {
"context": {"user": {"login": "timmy"}, "issues": [], "pull_requests": []},
"events": [{"id": 7}],
"notifications": [],
"revisions": {
"context": "0123456789abcdef.1",
"events": "fedcba9876543210.2",
"notifications": "0011223344556677.3",
},
"freshness": {
"fresh_for_seconds": 8,
"sections": {
"context": {"degraded": False, "age_seconds": 2},
"events": {"degraded": False, "age_seconds": 2},
"notifications": {"degraded": False, "age_seconds": 2},
},
},
}, "secondHasSnapshot": False}
def test_progressive_inflight_snapshot_survives_workspace_handoff_and_stop():
harness = f"""
const fs=require('fs'); const vm=require('vm');
const document={{
querySelector:selector=>selector==='#my-work-list'?{{innerHTML:''}}:selector==='#my-work-status'?{{textContent:''}}:null,
querySelectorAll:()=>[],
}};
const context={{module:{{exports:{{}}}},exports:{{}},console,URL,document}}; vm.createContext(context);
vm.runInContext(fs.readFileSync({json.dumps(str(MY_WORK))},'utf8'),context);
context.buildMyWork=context.module.exports; context.module={{exports:{{}}}};
vm.runInContext(fs.readFileSync({json.dumps(str(MODULE))},'utf8'),context);
let resolveSnapshot;
const snapshot={{context:{{user:{{login:'timmy'}},issues:[],pull_requests:[]}},events:[],notifications:[]}};
const flow=context.module.exports({{document,fetchSnapshot:()=>new Promise(resolve=>{{resolveSnapshot=resolve;}})}});
(async()=>{{
const started=flow.start();
await Promise.resolve();
const handoff=flow.handoff();
flow.stop();
resolveSnapshot(snapshot);
const transferred=await handoff.liveSnapshotPromise;
await started;
console.log(JSON.stringify({{transferred}}));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
result = subprocess.run(["node", "-e", harness], check=True, capture_output=True, text=True)
assert json.loads(result.stdout) == {"transferred": {
"context": {"user": {"login": "timmy"}, "issues": [], "pull_requests": []},
"events": [],
"notifications": [],
}}