Skip to content

v2.7.0

Choose a tag to compare

@jhoward321 jhoward321 released this 27 Aug 18:20
· 4 commits to master since this release

Changed

  • A long-lived SSE stream severed mid-frame is now logged at DEBUG instead of WARN. Such a sever is routine behind a CDN or reverse proxy: the client reconnects and the server replays a full sync snapshot, so no configuration is missed and nothing is degraded — but reporting it at WARN turned ordinary operation into a recurring alarm. A stream that never opened is still logged at WARN, and the fallback-to-polling warning is unchanged, so a genuinely broken stream stays visible. (#2457)

Fixed

  • An explicit client.flush() no longer opens a second drain loop while one is already running. The in-flight latch added for #2456 guarded only the batch-size trigger, so the periodic flush, an explicit client.flush() and a size-triggered flush could enter the loop together — two request streams against an endpoint the backoff gate exists to protect, and worse, a success in one cleared the gate a failure in the other had just armed, re-opening the one-request-per-evaluation behaviour outright. A caller arriving while a drain is running now waits for it and returns, matching the js and node SDKs. Shutdown still bypasses coalescing, because it is the last drain there will ever be. (#2477)

  • A Before/After date operand that resolves outside the representable date range now matches nothing, where it previously resolved to a real instant. The evaluation engine parses with DateTimeOffset.TryParse, so its accepted range is 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999Z and it matches nothing outside that; this SDK resolved past both ends, so a single saved rule served different variations to two users purely by which SDK their service ran. (#2500)

  • The two reachable shapes are a year-zero operand and an operand carried out of range by its offset. 0000-01-01 is inside the ISO grammar and is a real proleptic date (0000-02-29 exists — year 0 is divisible by 400), so neither #2480's grammar guard nor #2491's calendar-day check excluded it. Separately, [0-9]{4} constrains only the written year while a timezone offset moves the resolved instant, so 0001-01-01T00:00:00+05:00 fell below the floor and 9999-12-31T23:59:59-05:00 rose above the ceiling from years the grammar allows. The check therefore runs on the resolved instant — deliberately unlike #2491's, which runs on the written date. (#2500)

  • The exact boundaries remain accepted: 0001-01-01, 0001-01-01T05:00:00+05:00, 9999-12-31T23:59:59Z and 9999-12-31T18:59:59-05:00 all still resolve. (#2500)

If you have a targeting rule using one of these operands, rewrite it as the date you meant. The Management API has rejected them on write since #2480 (PortableDateOperand round-trips every grammar-matched operand through the engine's own parser, so it inherits the range bound), meaning only rules saved before that release can carry one.

  • The first SSE reconnect after a healthy stream drops is now jittered to [d/2, d], like every other backoff level. The drops this absorbs are fleet-wide — a single edge event severs every stream at once — so every client re-entered the backoff together and waited an identical delay, republishing the drop's own synchronisation as a reconnect spike one backoff later. Measured in production: a drop spread across 2.5–3.0 ms produced a reconnect spread of 26–46 ms. The delay never exceeds the previous one and stays strictly positive, so a stream that fails immediately still cannot busy-loop. (#2508)