When Redis rejected a command while queueing it (OOM, READONLY, NOPERM, MISCONF, wrong arity), MultiExec threw AbortedMultiExecException without sending DISCARD.
A transaction block discards on the way out, the fluent interface didn't, so the connection stayed in MULTI and every later command on the client returned QUEUED without running.
The fluent interface now discards the transaction, or closes the connection if DISCARD fails too.
Until discard() is called, the aborted MultiExec refuses new commands and execute(), so a caller that catches the exception can't commit only the commands queued after the failed one.
Cluster connections skip the abort path: their errors before execute()
come from the client and nothing is queued on a node yet. watch() refuses
to run on an aborted transaction and unwatch() sends nothing, so only
discard() makes it usable again. Every discard on the way out closes the
connection when DISCARD fails.
Retrying one of its commands on a new connection runs it outside of the
transaction: with Sentinel even without the retry option, since
SentinelReplication retries on its own. A transaction block then threw
with one command already written, and a CAS transaction overwrote a
change made after WATCH, because MULTI and EXEC ran on a connection
that watched nothing.
MultiExec::unwatch() now goes through the strategy before MULTI, a held connection that is no longer open fails instead of reconnecting outside the transaction, a StreamInitException releases it too, and replication holds getCurrent().
In CAS mode the first command initializes the transaction without sending MULTI, so MultiExec::unwatch() now checks for CAS too.
* Added support for Set Expiration commands
* Skipped test no longer valid since 8.11
* changelog [skip ci]
---------
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
* Fix quadratic-time parsing of MONITOR events
Anchor the metadata pattern in `Monitor\Consumer` to the start of the
event. The unanchored pattern scanned command arguments even for events
with a valid header, because `preg_replace_callback()` searches once
more after reaching its limit. With PCRE JIT disabled, or with older
PCRE, a 64 KB argument of `[1 ` sequences took seconds to parse.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Remove comment about metadata matching
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Relay::select() throws a TypeError for anything but an integer, where
other connections get an error response from the server. Wrap the call
and return the same error response, so the existing test runs against
Relay and no longer needs a Relay-only counterpart.
Relay warns before sending SELECT for out-of-range databases, so that
test keeps its Relay-specific counterpart.
Disconnect interrupted pipeline connections before they can be reused,
discard remaining commands, and reset running state after PHP errors.
Preserve the original failure when connection cleanup also fails.
Clear the cached connection resource when Relay is closed so the next
command reconnects and replays connection initialization. This fixes
client reuse after an interrupted pipeline disconnects the connection.
queryClusterNodeForSlotMap() overrides Retry's default catchable exception
list with [ConnectionException::class]. StreamInitException extends
PredisException directly, so a CLUSTER SLOTS refresh that cannot open a
connection to the node it was redirected to is neither retried nor allowed
to fall back to another node: the fail callback that evicts the unreachable
node never runs, and the exception escapes uncaught.
php 8.6 deprecates spl_object_hash(). ConnectionErrorProof only uses it as an array key for per-connection exceptions, so spl_object_id() is a drop-in replacement. added a dedicated test for the pipeline.
parseDouble() returned positive INF for the RESP3 payload ',-inf',
inverting the sign. The value is reachable with protocol=3, for
example ZSCORE on a member whose score is -inf.
The existing infinity test asserted only is_infinite(), which cannot
detect the sign inversion, so it now checks exact values.
NaN payloads keep their current behavior; that is addressed
separately.
* Added support for MAXCOUNT and MAXSIZE arguments for XREAD and XREADGROUP
* Improve deprecation, by introducing deprecated real methods
* Renamed from XREAD_NEW to XREAD_V4