From 58e81a5718ed733f8885c2fe86af1d5aa556ad57 Mon Sep 17 00:00:00 2001 From: VrianCao <45995071+VrianCao@users.noreply.github.com> Date: Tue, 14 Apr 2026 11:05:32 +0000 Subject: [PATCH] Revert "Merge pull request #70 from VrianCao/perf/inline-homepage-refresh" This reverts commit 4a545ff9689205859f56e7aea33d51168e2f6495, reversing changes made to 543da3a6f6c02e84e77348efa8f72b4397e982bc. --- apps/worker/src/scheduler/scheduled.ts | 44 ++++++++++++++++++++++---- apps/worker/test/scheduled.test.ts | 37 +++++++++++++++++----- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/apps/worker/src/scheduler/scheduled.ts b/apps/worker/src/scheduler/scheduled.ts index 9f0a250..b940899 100644 --- a/apps/worker/src/scheduler/scheduled.ts +++ b/apps/worker/src/scheduler/scheduled.ts @@ -33,14 +33,37 @@ const PERSIST_BATCH_SIZE = 25; // Look back a bit so maintenance start/end notifications are not missed if a tick is delayed. const MAINTENANCE_EVENT_LOOKBACK_SECONDS = 10 * 60; +async function refreshHomepageSnapshotViaService(env: Env): Promise { + if (!env.SELF) { + throw new Error('SELF service binding missing'); + } + if (!env.ADMIN_TOKEN) { + throw new Error('ADMIN_TOKEN missing'); + } + + const res = await env.SELF.fetch( + new Request('http://internal/api/v1/internal/refresh/homepage', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain; charset=utf-8', + }, + body: env.ADMIN_TOKEN, + }), + ); + + if (!res.ok) { + const text = await res.text().catch(() => ''); + throw new Error(`service refresh failed: HTTP ${res.status} ${text}`.trim()); + } +} + async function refreshHomepageSnapshotInline(env: Env, now: number): Promise { - const [{ computePublicHomepagePayload }, { refreshPublicHomepageSnapshotIfNeeded }] = - await Promise.all([ + const [{ computePublicHomepagePayload }, { refreshPublicHomepageSnapshot }] = await Promise.all([ import('../public/homepage'), - import('../snapshots/public-homepage'), + import('../snapshots'), ]); - await refreshPublicHomepageSnapshotIfNeeded({ + await refreshPublicHomepageSnapshot({ db: env.DB, now, compute: () => computePublicHomepagePayload(env.DB, now), @@ -682,9 +705,16 @@ export async function runScheduledTick(env: Env, ctx: ExecutionContext): Promise const now = Math.floor(Date.now() / 1000); const checkedAt = Math.floor(now / 60) * 60; const queueHomepageRefresh = () => - refreshHomepageSnapshotInline(env, now).catch((err) => { - console.warn('homepage snapshot: refresh failed', err); - }); + env.SELF + ? refreshHomepageSnapshotViaService(env).catch(async (err) => { + console.warn('homepage snapshot: service refresh failed', err); + await refreshHomepageSnapshotInline(env, now).catch((fallbackErr) => { + console.warn('homepage snapshot: refresh failed', fallbackErr); + }); + }) + : refreshHomepageSnapshotInline(env, now).catch((err) => { + console.warn('homepage snapshot: refresh failed', err); + }); const acquired = await acquireLease(env.DB, LOCK_NAME, now, LOCK_LEASE_SECONDS); if (!acquired) { diff --git a/apps/worker/test/scheduled.test.ts b/apps/worker/test/scheduled.test.ts index 4fea227..d082583 100644 --- a/apps/worker/test/scheduled.test.ts +++ b/apps/worker/test/scheduled.test.ts @@ -18,8 +18,8 @@ vi.mock('../src/notify/webhook', () => ({ vi.mock('../src/public/homepage', () => ({ computePublicHomepagePayload: vi.fn(), })); -vi.mock('../src/snapshots/public-homepage', () => ({ - refreshPublicHomepageSnapshotIfNeeded: vi.fn(), +vi.mock('../src/snapshots', () => ({ + refreshPublicHomepageSnapshot: vi.fn(), })); import type { Env } from '../src/env'; @@ -29,7 +29,7 @@ import { dispatchWebhookToChannels } from '../src/notify/webhook'; import { computePublicHomepagePayload } from '../src/public/homepage'; import { runScheduledTick } from '../src/scheduler/scheduled'; import { acquireLease } from '../src/scheduler/lock'; -import { refreshPublicHomepageSnapshotIfNeeded } from '../src/snapshots/public-homepage'; +import { refreshPublicHomepageSnapshot } from '../src/snapshots'; import { readSettings } from '../src/settings'; import { createFakeD1Database, type FakeD1QueryHandler } from './helpers/fake-d1'; @@ -160,7 +160,7 @@ describe('scheduler/scheduled regression', () => { resolved_incident_preview: null, maintenance_history_preview: null, } as never); - vi.mocked(refreshPublicHomepageSnapshotIfNeeded).mockResolvedValue(false); + vi.mocked(refreshPublicHomepageSnapshot).mockResolvedValue(undefined); vi.mocked(runHttpCheck).mockResolvedValue({ status: 'up', latencyMs: 21, @@ -205,19 +205,40 @@ describe('scheduler/scheduled regression', () => { expect(readSettings).toHaveBeenCalledTimes(1); expect(waitUntil).toHaveBeenCalledTimes(1); await Promise.all(waitUntil.mock.calls.map((call) => call[0] as Promise)); - expect(refreshPublicHomepageSnapshotIfNeeded).toHaveBeenCalledWith({ + expect(refreshPublicHomepageSnapshot).toHaveBeenCalledWith({ db: env.DB, now: expectedNow, compute: expect.any(Function), }); - const refreshArgs = vi.mocked(refreshPublicHomepageSnapshotIfNeeded).mock.calls[0]?.[0]; + const refreshArgs = vi.mocked(refreshPublicHomepageSnapshot).mock.calls[0]?.[0]; expect(refreshArgs).toBeDefined(); await refreshArgs?.compute(); expect(computePublicHomepagePayload).toHaveBeenCalledWith(env.DB, expectedNow); }); + it('self-invokes homepage refresh via service binding when SELF is configured', async () => { + const env = createEnv({ dueRows: [] }) as unknown as Env; + env.ADMIN_TOKEN = 'test-admin-token'; + const selfFetch = vi.fn().mockResolvedValueOnce(new Response('ok', { status: 200 })); + env.SELF = { fetch: selfFetch } as unknown as Fetcher; + const waitUntil = vi.fn(); + + await runScheduledTick(env, { waitUntil } as unknown as ExecutionContext); + + expect(waitUntil).toHaveBeenCalledTimes(1); + await Promise.all(waitUntil.mock.calls.map((call) => call[0] as Promise)); + + expect(selfFetch).toHaveBeenCalledTimes(1); + const req = selfFetch.mock.calls[0]?.[0] as Request; + expect(req).toBeInstanceOf(Request); + expect(req.method).toBe('POST'); + expect(new URL(req.url).pathname).toBe('/api/v1/internal/refresh/homepage'); + expect(await req.text()).toBe('test-admin-token'); + expect(refreshPublicHomepageSnapshot).not.toHaveBeenCalled(); + }); + it('logs homepage snapshot refresh failures without breaking the tick', async () => { - vi.mocked(refreshPublicHomepageSnapshotIfNeeded).mockRejectedValueOnce( + vi.mocked(refreshPublicHomepageSnapshot).mockRejectedValueOnce( new Error('snapshot refresh failed'), ); @@ -312,7 +333,7 @@ describe('scheduler/scheduled regression', () => { expect(waitUntil).toHaveBeenCalledTimes(1); await Promise.all(waitUntil.mock.calls.map((call) => call[0] as Promise)); - expect(refreshPublicHomepageSnapshotIfNeeded).toHaveBeenCalledTimes(1); + expect(refreshPublicHomepageSnapshot).toHaveBeenCalledTimes(1); }); it('passes explicit response assertion modes through scheduled HTTP checks', async () => {