# Changelog of Yelp Scraper — Leads, Reviews & Contacts (`sleek_waveform/yelp-scraper`) Actor

- **URL**: https://apify.com/sleek\_waveform/yelp-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/sleek\_waveform/yelp-scraper.md

## Changelog

### 2026-08-10

Fixes a run that was killed at the platform timeout (`TIMED_OUT`) after going
idle mid-page. It had already written 16 good businesses; nothing stopped work
before the kill, so the whole run was reported as a failure.

- **Never hit the platform timeout again.** The actor now derives a deadline from
  the run's own `timeoutAt`, stops starting new work once it passes, and finishes
  cleanly with whatever it collected — a `SUCCEEDED` run with partial results
  instead of a `TIMED_OUT` failure. The margin scales with the window (10%,
  clamped to 5-20s) so short QA validation runs are not eaten by a fixed reserve.
- **A stalled listing can no longer hold the pipeline.** Each business is bounded
  by its own time budget; one that outlives it is abandoned with a warning rather
  than holding all 15 concurrent workers open. This was the actual shape of the
  failure — 4m37s of silence at 0.9% CPU, waiting on a single await that never
  settled. (HTTP fetches were already bounded at 12s/attempt; the stall was in a
  non-HTTP await, where the Apify client retries silently for minutes.)
- **Watchdog backstop.** If something hangs where no loop can observe the
  deadline, a timer finalizes the run and exits 0 before the platform kills it.
- **Fixed a proxy socket leak.** Every request built a `ProxyAgent` that was never
  closed; undici holds keep-alive connections until an agent is closed, so each
  request leaked one TCP connection to `proxy.apify.com` for the life of the run
  (measured: 20 requests -> 20 sockets still open, 0 after the fix). A fresh agent
  per request is kept deliberately — the residential proxy assigns an exit IP per
  connection, so pooling would pin every rotated retry to the same IP.
- **Bounded review pagination.** Reviews with empty text are skipped, so the
  "collect N reviews" loop could page forever on a business with thousands of
  them. It now stops a few pages past the ideal count.

### 2026-07-12

- Fix `maxResults` to apply per search term/location pair (matches INPUT\_SCHEMA and README); global dedup unchanged.
- Prevent concurrent workers from exceeding per-search `maxResults` via slot reservation (`run-scheduling.ts`).
- Parallelize business detail page + review GraphQL fetches when both are needed (lower wall-clock on review cohorts).
- Parallelize independent search term×location pipelines (up to 3 concurrent) for multi-city inputs.
