• v0.29.2 4491f3736e

    v0.29.2
    All checks were successful
    CI / gate (push) Successful in 1m5s
    CI / image (push) Successful in 36s
    Stable

    joeyr released this 2026-09-30 20:12:49 -05:00 | 217 commits to main since this release

    Fixed

    • A Riot call that fails for good costs its item, not the night. A seed
      page, a seed's match list or a match that still fails after the client's
      retries is now logged and skipped, and the crawl moves on. Before, any such
      failure — a network drop longer than the retry backoff, a run of 5xx, a 400 on
      one match id — threw out of the crawl and cost all six Riot artifacts the
      night, although every row already stored was good. A failed match is not
      marked seen, so a later night whose lookback still covers it can try again.
      Failures are counted as failures on the crawl's summary line.

      Two things still end the crawl. A 401 or 403 throws as before: a bad key fails
      every call alike and is a fault on the first night. And
      MAX_CONSECUTIVE_FAILURES (20) in a row — after retries, ten minutes or more
      in which nothing succeeded — stops it with stoppedBy: 'failures', and the
      builders publish from what was stored. If nothing was, all six artifacts
      record a fault naming the last failure, not the quiet "no new rows" of a night
      that simply deduplicated to nothing.

    • Riot errors name the endpoint that failed. A request that died in transport
      after its retries surfaced undici's bare terminated, which is all a
      publish-state reason could say. It is now a RiotApiError reading
      match: transport failure after retries (terminated), with the socket error
      kept as cause, and every Riot error opens with its endpoint the same way —
      league-exp, match ids, match or timeline. Never the URL: these messages
      reach the repo's commit status, and a match-list URL carries a puuid.

    • TIMELINE_MAX_REQUESTS counts requests, not timelines. A timeline that
      needed retries — after a 429, a 5xx, or a body that died mid-read — spent up to
      six requests and was counted as one, and a timeline that failed was not
      counted at all. The budget now adds what each call actually spent, logged as
      timelineRequests. The night's last timeline can still run over by its own
      retries, since those are not known until the call ends.

    • Shutdown no longer waits out the Riot client. Its retry backoff, a 429's
      one-minute yield and the pacing after one all ignored SIGTERM, so a redeploy
      could sit in a wait longer than Swarm's stop grace period and be killed
      mid-match instead of stopping cleanly. Those waits now end on shutdown and the
      crawl stops as signal. A request already in flight is still left to finish.

    • A non-numeric Retry-After no longer skips the 429 backoff. The header may
      be an HTTP-date, which made the wait NaN and the sleep zero. It now falls
      back to the full 60-second yield.

    • A 429 on the last attempt throws at once. It used to wait out the yield
      before throwing anyway — a minute or more for nothing, and at boot for the
      one-shot preflight probe. The rate-limit penalty is still applied.

    • Retried transport failures are logged. Each retry now logs a warning with
      the URL, the attempt and the error, so a reset the retries recovered from is
      visible rather than indistinguishable from a clean night.

    Downloads