dev #74

Merged
root merged 3 commits from dev into main 2026-06-01 22:10:03 +03:00
Owner
No description provided.
root added 3 commits 2026-06-01 22:09:57 +03:00
Two follow-ups to the warm-pool patch:

* Semaphore 1 → 3. Playwright contexts are isolated, the captureToPool
  site/port allocation is synchronous (no race), and concurrent user
  clicks that all miss the pool no longer serialize behind a single
  ~5s capture. Peak memory grows from one context to three; each is
  short-lived.

* Capture-time validation. After Playwright extracts the JWT, do one
  cheap upstream call (/car/info with the public demo VIN) through the
  same proxy port before pushing the slot to the pool. DataImpulse
  occasionally rotates to IPs the partner widget can load but the
  upstream API can't reach, or that get instantly 401/403'd; those
  ports used to spend 30s timing out on the first real user click.
  Failures rotate to the next site within the existing 4-retry budget.

Adds ~1s to each successful capture; saves up to 30s per dead slot.
Concurrent captures are bound by how many distinct partner sites we can
drive in parallel — each capture needs its own site so they don't collide
on the synchronous siteIndex round-robin. Ports are effectively unlimited
(10000-10999) and Playwright contexts are isolated, so the previous
arbitrary cap of 3 left headroom on the table when the pool is cold and
N>3 user clicks race in at once.

Tying the cap to JWT_SITES.length also means future site additions or
removals auto-adjust the ceiling.
feat(pcat-auth): cache JWT slot in Redis (PL24-style cross-restart hydration)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
dcf7e068c9
A captured slot now lives in Redis under `pcat:jwt:slot` for the JWT's
remaining lifetime (minus a 60s safety buffer). On module init we try
Redis before launching Playwright — if a fresh slot is there we adopt it
and schedule its refresh, skipping the ~5s capture entirely. After every
successful capture+validation we publish to Redis so the next restart (or
any sibling pod) can inherit. invalidateSession deletes the Redis copy
because a 401/403 means the cached IP-binding is dead.

Token is still IP-bound to its proxyPort. If a hydrating container reads
the slot but the proxy has rotated away from the captured IP, the next
upstream call 401s and the existing invalidateSession fallback re-captures
locally — so worst case = today's cold-capture behavior, never worse.

Note: dev and prod use separate Redis instances. This patch reaches PL24
parity (same-env redeploy hydration); a true dev↔prod shared cache would
need either an external Redis or an internal-token bridge.
root merged commit ec5cfae4e6 into main 2026-06-01 22:10:03 +03:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: root/sase.tr#74