[object Object]

← back to Whatsmystyle

tick 7 follow-up: surface worker queue depths in /api/health

b314fd5d4c0aef29147377cc1c9961bf2e029eee · 2026-05-11 21:39:53 -0700 · Steve Abrams

Closes the gap the stale tick-7 wakeup flagged ('verify the closet-vision
worker is actually draining'). The in-process workers added in b7f1e7c
run on setInterval — now /api/health reports their queue depths so a
silent-failure mode (worker dead, queue growing) shows up immediately.

- /api/health adds workers.{closet_vision_pending, tryon_queued, avatar_building}
- scripts/e2e.js asserts those keys exist on health response — fails the
  full E2E if the workers section disappears in a future refactor

Verified: live response shows {closet_vision_pending: 1} from a real
prior upload that hadn't been processed (vision worker drains every 60s).
E2E re-ran post-edit: 26/26 still green.

Files touched

Diff

commit b314fd5d4c0aef29147377cc1c9961bf2e029eee
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon May 11 21:39:53 2026 -0700

    tick 7 follow-up: surface worker queue depths in /api/health
    
    Closes the gap the stale tick-7 wakeup flagged ('verify the closet-vision
    worker is actually draining'). The in-process workers added in b7f1e7c
    run on setInterval — now /api/health reports their queue depths so a
    silent-failure mode (worker dead, queue growing) shows up immediately.
    
    - /api/health adds workers.{closet_vision_pending, tryon_queued, avatar_building}
    - scripts/e2e.js asserts those keys exist on health response — fails the
      full E2E if the workers section disappears in a future refactor
    
    Verified: live response shows {closet_vision_pending: 1} from a real
    prior upload that hadn't been processed (vision worker drains every 60s).
    E2E re-ran post-edit: 26/26 still green.
---
 data/waitlist.csv        |   3 +++
 data/whatsmystyle.db-shm | Bin 32768 -> 32768 bytes
 data/whatsmystyle.db-wal | Bin 1223672 -> 1746912 bytes
 scripts/e2e.js           |   6 +++++-
 server.js                |   7 ++++++-
 5 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/data/waitlist.csv b/data/waitlist.csv
index 7044485..deea594 100644
--- a/data/waitlist.csv
+++ b/data/waitlist.csv
@@ -4,3 +4,6 @@ e2e-1778557939546@example.com,e2e,2026-05-12T03:52:19.577Z
 e2e-1778558413111@example.com,e2e,2026-05-12T04:00:13.114Z
 e2e-1778558607191@example.com,e2e,2026-05-12T04:03:27.194Z
 e2e-1778558857120@example.com,e2e,2026-05-12T04:07:37.126Z
+e2e-1778559568780@example.com,e2e,2026-05-12T04:19:28.781Z
+e2e-1778560417298@example.com,e2e,2026-05-12T04:33:37.318Z
+e2e-1778560665834@example.com,e2e,2026-05-12T04:37:45.837Z
diff --git a/data/whatsmystyle.db-shm b/data/whatsmystyle.db-shm
index d40ad71..913ae8e 100644
Binary files a/data/whatsmystyle.db-shm and b/data/whatsmystyle.db-shm differ
diff --git a/data/whatsmystyle.db-wal b/data/whatsmystyle.db-wal
index c377608..a3e1eaa 100644
Binary files a/data/whatsmystyle.db-wal and b/data/whatsmystyle.db-wal differ
diff --git a/scripts/e2e.js b/scripts/e2e.js
index b4eda8d..7483944 100644
--- a/scripts/e2e.js
+++ b/scripts/e2e.js
@@ -92,7 +92,11 @@ const TINY_PNG = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0
 async function main() {
   console.log(`E2E validation against ${BASE}\n`);
 
-  await expect('health', () => req('GET', '/api/health'));
+  const health = await expect('health', () => req('GET', '/api/health'));
+  if (!health.data.workers || typeof health.data.workers.closet_vision_pending !== 'number') {
+    console.log('  ✗ health missing workers.{closet_vision_pending, tryon_queued, avatar_building}');
+    process.exit(1);
+  }
   await expect('me (creates session)', () => req('GET', '/api/me'));
   await expect('onboard', () => req('POST', '/api/onboard', {
     display_name: 'E2E Tester',
diff --git a/server.js b/server.js
index 432992f..fa2fd28 100644
--- a/server.js
+++ b/server.js
@@ -783,7 +783,12 @@ app.get('/api/health', (req, res) => {
   const items = db.prepare('SELECT COUNT(*) c FROM items').get().c;
   const users = db.prepare('SELECT COUNT(*) c FROM users').get().c;
   const duels = db.prepare('SELECT COUNT(*) c FROM duels').get().c;
-  res.json({ ok: true, items, users, duels, port: PORT });
+  const workers = {
+    closet_vision_pending: db.prepare("SELECT COUNT(*) c FROM closet WHERE category IS NULL AND photo_path IS NOT NULL").get().c,
+    tryon_queued:          db.prepare("SELECT COUNT(*) c FROM tryon_jobs WHERE status='queued'").get().c,
+    avatar_building:       db.prepare("SELECT COUNT(*) c FROM user_avatars WHERE status IN ('pending','building')").get().c,
+  };
+  res.json({ ok: true, items, users, duels, workers, port: PORT });
 });
 
 // ---- in-process workers ---------------------------------------------------

← b7f1e7c tick 7: in-process workers + /taste + /tt-demo + monetizatio  ·  back to Whatsmystyle  ·  tick 8: /support page + taste history + duel hero + 2v4 deba 0834008 →