Skip to content

v2.15.0

Choose a tag to compare

@bpacholek bpacholek released this 07 Oct 04:25
· 70 commits to main since this release

Minor release. An operation that reads the socket while it waits for a result of its own now takes what is already queued for its own subscription before it reads (#179). A handler of yours that polls a SubscriptionQueue for a message that arrived in the same chunk, behind the message it handles, gets it at once; before, that message waited for the handler to return and the poll timed out. Likewise an operation whose message another fiber's read had queued behind a handler that awaits an HTTP or database call now gets it at once, rather than when that handler returns.

Upgrading is recommended if your handlers poll, fetch or consume beside the subscription they handle, or if your handlers await slow calls while other fibers poll, fetch or consume. There are no API changes; one note from 2.12.0 is reversed, below. symfony-nats-messenger 5.4.1 works with this release unchanged.

Upgrade notes

  • An operation takes what is already queued for its subscription, also while a handler ahead of it is still running. 2.12.0 said an operation gets its message once the in-order delivery reaches it; now a SubscriptionQueue poll, fetchBatch()/fetchNext(), directGetBatch(), the pull consumer and Key/Value keys()/history() take their subscription's queued messages first. The only reorder is of the operation's own subscription ahead of other subscriptions' messages queued with it; its messages go into a buffer the operation reads, not to a handler of yours, so no handler invocations between your subscriptions change order. The take covers what another fiber's read has already queued when the operation looks: a poll whose own read brings the chunk still runs the handler ahead of its message first, and while a reconnect is under way the operation waits for it first, within its timeout, then takes what is queued. A sid whose delivery is under way is left to that delivery; during a disconnect() the queued messages are the close's to discard; an own-subscription overflow under SlowConsumerPolicy::Error met by the take fails the operation; a poll concurrent with unsubscribe() may still return a message received before the UNSUB. request()/requestMany() and your own reads are unchanged.

Fixed

  • A handler polling for a message queued behind its own delivery waited out its timeout (#179). The message was queued in the connection behind the delivery the handler ran in, and nothing delivered it until the handler returned. The operation's read now takes what is already queued for its own subscription before it reads, and returns it; the same take ends the wait of an operation whose message another fiber's read had queued behind a handler that awaits.

Quality gates

  • PHPStan level 8.
  • 2789 unit tests (with data sets) on PHP 8.2 to 8.5, 149 live integration tests and 48 Behat scenarios.
  • All 45 runnable examples executed against a live server.
  • Statement coverage 99.02% from the unit suite (95% floor enforced in CI) and 99.09% combined (97% floor).
  • Infection covered MSI 93.6% over the 3870 mutants it ran (90% floor enforced in CI); it skipped 3906 of the 7776 it generated as too slow, so the score does not include them.
  • Every CI job passed on the first attempt. Every fix has tests that fail on the old code: the handler's poll returned nothing at its timeout, and the operations returned only when the handler ahead of them had finished. On a real server with AmpSocketTransport a handler polling its own queue got the message in 0.1 ms, where it got nothing at 1.0 s before.
  • The change was reviewed for semantics and for interleavings by two independent reviewers, and their findings were applied; the 2.14.0 reconnect tests whose staging this changes were restaged and still pass.
  • symfony-nats-messenger 5.4.1's suites pass against this release: PHPStan level max, 528 unit tests, 52 functional scenarios against live NATS and 5 examples.

The full record is in the CHANGELOG.