Upstream predis/predis state of the touched files before 33fb123441
This commit is contained in:
commit
7c87a97e67
3 files changed
+741
No files matched your search
+460
@@ -0,0 +1,460 @@
|
||||
## Changelog
|
||||
|
||||
## Unreleased
|
||||
### Added
|
||||
- Added optional `CELL_SIZE` argument for `CMS.INITBY(DIM|PROB)` (#1729)
|
||||
- Added `BLESS *` command family (#1733)
|
||||
- Added testing with a new HNSW compression (#1737)
|
||||
|
||||
### Fixed
|
||||
- Fixed client iteration with master/slave and Sentinel replication (#923)
|
||||
- Fixed `*StreamConnection` looping forever when closed in the middle of a bulk reply (#1731)
|
||||
- Fixed cluster CAS transactions returning transaction objects for reads and sending `MULTI` twice
|
||||
- Fixed `MultiExec::multi()` being ignored as the first call of a CAS transaction
|
||||
- Fixed cleanup of empty transactions and transaction callbacks that throw PHP errors
|
||||
- Fixed `spl_object_hash()` deprecation on PHP 8.6 in `ConnectionErrorProof` pipeline
|
||||
|
||||
### Security
|
||||
- Fixed aborted cluster transactions leaving node connections in `MULTI`
|
||||
|
||||
## v3.6.1 (2026-09-17)
|
||||
### Fixed
|
||||
- Fixed RESP3 double parsing returning positive `INF` for `-inf` payloads (#1716)
|
||||
- Fixed `client_info` connection parameter being ignored (#1722)
|
||||
- Fixed `Stream::write()` and `read()` leaving a dead connection when a host error handler throws exception (#1725)
|
||||
|
||||
### Security
|
||||
- Deprecated `CommandInterface::deserializeCommand()` (CVE GHSA-w6f5-v2h6-g786)
|
||||
- Fixed CRLF command smuggling and node misrouting in `AbstractAggregateConnection::write()` and `CommandInterface::deserializeCommand()` (CVE GHSA-w6f5-v2h6-g786)
|
||||
|
||||
## v3.6.0 (2026-08-14)
|
||||
### Added
|
||||
- Added support for new TS commands + Indonesian language support integration test (#1695)
|
||||
- Added support for new COLLECT reducer for FT.AGGREGATE (#1699)
|
||||
- Added support for `SDIFFCARD` and `SUNIONCARD` command
|
||||
- Added support for `MAXCOUNT` and `MAXSIZE` arguments for `XREAD` and `XREADGROUP`
|
||||
- Added support for `TS.READ` command
|
||||
- Added support for `EXCLUDEEMPTY` argument for `TS.MRANGE` and `TS.MREVRANGE` commands
|
||||
- Added explicit testing for FT.SEARCH timeout policies
|
||||
- Added support for `TS.QUERYLABELS` command
|
||||
- Added support for `LMOVEM` and `BLMOVEM` commands
|
||||
- Added support for `FT.ALIASLIST` command
|
||||
- Added stream commands to ClusterStrategy
|
||||
- Added vector sets commands to ClusterStrategy
|
||||
- Added experimental support for `HIMPORT` bulk hash import feature (API may change in a future release)
|
||||
|
||||
### Changed
|
||||
- Added `OBJECT` and hash field expiration commands to `ClusterStrategy`
|
||||
- Make `ZMSCORE` command prefixable and add to `ClusterStrategy` (#1692)
|
||||
|
||||
### Fixed
|
||||
- Fixed Sentinel does not wipe servers on exception caused (#1694)
|
||||
- Fixed `@method cmsincrby()` annotation
|
||||
|
||||
## v3.5.1 (2026-06-11)
|
||||
### Added
|
||||
- Expose `pipeline()` API via `ClientInterface` (#1686)
|
||||
|
||||
### Fixed
|
||||
- Allow `UNLINK` to accept an array of keys (#1687)
|
||||
- Fixed `Client::(un)pack()` return types
|
||||
|
||||
## v3.5.0 (2026-06-02)
|
||||
### Added
|
||||
- Added support for `XNACK` command (#1666)
|
||||
- Added support for `INCREX` command (#1674)
|
||||
- Added support for `UNLINK` command (#1680)
|
||||
- Added support for `AR*` array commands (#1672)
|
||||
- Handle Redis Cluster `-READONLY` responses failover events (#1656)
|
||||
- Added `FPHA` argument for `JSON.SET` command (#1661)
|
||||
- Added new `COUNT` aggregator for Sorted Set commands (#1668)
|
||||
- Added support for multiple aggregators for `TS.range` commands (#1670)
|
||||
|
||||
### Changed
|
||||
- Include command name in unsupported container command error messages (#1653)
|
||||
|
||||
### Fixed
|
||||
- Fixed handling of gap slots in `SlotMap::offsetUnset()` (#1660)
|
||||
- Fixed `ZRANGE` to include 6.2 arguments (#1662)
|
||||
- Fixed Sentinel retry to narrow retryable exceptions to `CommunicationException` (#1665)
|
||||
- Fixed `SENTINEL SLAVES` RESP3 incompatible response (#1676)
|
||||
|
||||
## v3.4.2 (2026-03-09)
|
||||
### Changed
|
||||
- Switch to `static` closures
|
||||
|
||||
### Fixed
|
||||
- Fixed Sentinel `getParameters()` executed on string configuration (#1649)
|
||||
- Fixed Sentinel discovery methods not catching `StreamInitException` on connection failure (#1650)
|
||||
|
||||
## v3.4.1 (2026-02-23)
|
||||
### Added
|
||||
- Added `upstream_driver` option for CLIENT SETINFO upstream reporting (#1645)
|
||||
- Made `H(P)TTL` commands prefixable (#1639)
|
||||
- Made `(B)LMPOP` commands prefixable (#1643)
|
||||
|
||||
### Fixed
|
||||
- Fixed Sentinel `getParameter()` call on array error (#2423)
|
||||
- Removed deprecated `static` from callables (#1642)
|
||||
|
||||
## v3.4.0 (2026-02-11)
|
||||
### Added
|
||||
- Added optional retry support (#1616)
|
||||
- Added support for `VRANGE` command (#1623)
|
||||
- Added support for idempotent stream API (#1632)
|
||||
- Added support for `HOTKEYS` container command (#1630)
|
||||
|
||||
### Fixed
|
||||
- Fixed `[L|R]PUSHX` variadic arguments normalization (#1633)
|
||||
- Fixed wrong `@param` annotation in `Parameters` (#1614)
|
||||
- Made `ZRANDMEMBER` prefixable (#1621)
|
||||
- Improve connection handshake by pipelining commands (#1622)
|
||||
|
||||
## v3.3.0 (2025-11-24)
|
||||
### Added
|
||||
- Added cluster support for `XADD`, `XDEL` and `XRANGE` (#1587)
|
||||
- Added prefixable interface for `HEXPIRE` and `HEXPIRETIME` (#1592)
|
||||
- Added new experimental CAS/CAD functionality (#1609)
|
||||
- Added temporary `XREADGROUP_CLAIM` command (#1608)
|
||||
- Added support for `MSET` command (#1610)
|
||||
- Added experimental support for `FT.HYBRID` (#1607)
|
||||
|
||||
### Changed
|
||||
- Improved compatiblity with Relay (#1597)
|
||||
- Refactor pipeline data writing depends on connection type (#1586)
|
||||
|
||||
## v3.2.0 (2025-08-05)
|
||||
### Added
|
||||
- Added support for `XDELEX` and `XACKDEL` (#1580)
|
||||
- Added missing VSIM argument (#1582)
|
||||
|
||||
### Changed
|
||||
- Extended `XTRIM` and `XADD` commands with new parameters (#1580)
|
||||
|
||||
### Maintenance
|
||||
- Updated Redis 8.2 test image (#1583)
|
||||
- Added test coverage for updated Vamana (#1584)
|
||||
|
||||
## v3.1.0 (2025-07-22)
|
||||
### Added
|
||||
- Add experimental support for vector sets commands (#1550)
|
||||
- Added support for `XACK` command (#1555)
|
||||
- Added support for `XCLAIM` command (#1557)
|
||||
- Added support for `XPENDING` command (#1558)
|
||||
- Added support for `XSETID` command (#1559)
|
||||
- Added validation and support for the new `BITOP` command operations (#1566)
|
||||
|
||||
### Changed
|
||||
- Handle and retry `LOADING` errors from Sentinel replicas (#1536)
|
||||
- Retry all exceptions from Sentinel replicas (#1577)
|
||||
|
||||
### Fixed
|
||||
- Fixed PHP 8.4 deprecated call to `stream_context_set_option()` (#1545)
|
||||
- Fixed return type for `ZCOUNT` to be `int` (#1547)
|
||||
- Fixed throwing `CommunicationException` when stream is EOF (#1548)
|
||||
- Removed automatic `conn_uid` parameter assignment (#1552)
|
||||
- Fixed wrong command API call on prefix processing (#1554)
|
||||
- Fixed `XREAD` response parsing while read null (#1563)
|
||||
- Fixed `XINFO` command responses parsing (#1560)
|
||||
- Marked missing commands as Prefixable (#1576)
|
||||
|
||||
## v3.0.1 (2025-05-16)
|
||||
### Fixed
|
||||
- Send `default` user if only password is used for authentication (#1535)
|
||||
|
||||
## v3.0.0 (2025-05-02)
|
||||
### Added
|
||||
- ⚠️ Added support for transactions for clustered connections (#1497)
|
||||
- Added support for RESP3 communication protocol (#1047)
|
||||
- Added support for RESP3 push notifications (#1316)
|
||||
- Added support for Sharded Pub/Sub (#1303)
|
||||
- Added support for `XGROUP` commands (#1324)
|
||||
- Added support for `XREADGROUP` command (#1327)
|
||||
- Added support for `XAUTOCLAIM` command (#1328)
|
||||
- Added support for `XINFO` commands (#1331)
|
||||
- Added support for Redis 7.4 `XREAD` and `HSCAN` interface changes (#1452)
|
||||
|
||||
### Changed
|
||||
- ⚠️ Refactored Relay integration (#1423)
|
||||
- ⚠️ Changed interface of `CLIENT` command (#1337)
|
||||
- ⚠️ Changed interfaces for commands to support Redis 6.2 — 7.0 arguments (#1330)
|
||||
- ⚠️ Changed default search `DIALECT` to `2` (#1516)
|
||||
- ⚠️ Implemented PSR-7 compatible stream abstraction (#1450)
|
||||
- ⚠️ Improved pipeline abstractions (#1438)
|
||||
- ⚠️ Improved connection handshake (#1431)
|
||||
|
||||
### Fixed
|
||||
- Fixed single persistent connection using the same resource (#1512)
|
||||
|
||||
### Maintenance
|
||||
- Revisit incompatible tests against Relay (#1537)
|
||||
|
||||
## v2.4.0 (2025-04-30)
|
||||
### Added
|
||||
- Added new hash-field expiration commands (#1520)
|
||||
- Added missing `FT._LIST` and `BITFIELD_RO` commands (#1521)
|
||||
|
||||
### Changed
|
||||
- Update `WATCH` command to accept `string|string[]` (#1476)
|
||||
- Optimize cluster slotmap with compact slot range object (#1493)
|
||||
|
||||
### Fixed
|
||||
- Fixed `EVAL_RO` cluster support (#1449)
|
||||
- Fixed PHP 8.4 compatibility with `stream_context_set_option()` (#1503)
|
||||
- Prevent named arguments runtime failure (#1509)
|
||||
- Mark `GEOSEARCH` as read-only to ensure execution on replica (#1481)
|
||||
- Fixed protocol loss during redis cluster `MOVED` / `ASK` (#1530)
|
||||
|
||||
### Maintenance
|
||||
- Added CI testing with Redis 8.0 (#1510)
|
||||
- Added test coverage for compatibility with Redis 8.0 (#1513)
|
||||
- Use parallel on PHP-CS-Fixer (#1489)
|
||||
|
||||
## v2.3.0 (2024-11-21)
|
||||
### Added
|
||||
- Added `GeoShapeField` field (#1467)
|
||||
- Added hash expiration commands (#1456)
|
||||
- Added support for time series `IGNORE` filter (#1458)
|
||||
- Added `XREAD` commands (#1459)
|
||||
- Added `NOVALUES` argument support to `HSCAN` (#1459)
|
||||
- Added support for search `INDEXMISSING` and `INDEXEMPTY` arguments (#1464)
|
||||
|
||||
### Changed
|
||||
- Explicitly mark nullable parameters as nullable (#1448)
|
||||
- Filter out available replicas based on link status flag (#1440)
|
||||
- Respect `prefix` for `ZPOPMIN`, `ZPOPMAX`, `ZMSCORE`, `LMOVE`, `BLMOVE`, `SMISMEMBER` and `GEOSEARCH` (#1451, #1453, #1455, #1468)
|
||||
- Updated test infrastructure (#1510)
|
||||
-
|
||||
## v2.2.0 (2023-06-14)
|
||||
|
||||
Predis v2.2.0 introduces official support for [Redis Stack](https://redis.io/docs/stack/) as well as a [Relay](https://github.com/cachewerk/relay) integration for substantially [faster read performance](https://github.com/predis/predis/wiki/Using-Relay).
|
||||
|
||||
### Added
|
||||
- Added support for [Relay](https://github.com/predis/predis/wiki/Using-Relay) (#1263)
|
||||
- Added support for `FCALL_RO` command (#1191)
|
||||
- Added support for Redis `JSON`, `Bloom`, `Search` and `TimeSeries` module (#1253)
|
||||
- Added support for `ACL SETUSER, GETUSER, DRYRUN` commands (#1193)
|
||||
|
||||
### Changed
|
||||
- Minor code style and type-hint changes (#1311)
|
||||
|
||||
### Fixed
|
||||
- Fixed prefixes for `XTRIM` and `XREVRANGE` commands (#1230)
|
||||
- Fixed `fclose()` being called on invalid stream resource (#1199)
|
||||
- Fixed `BitByte` and `ExpireOptions` traits skip processing on null values (#1169)
|
||||
- Fixed missing `@return` annotations (#1265)
|
||||
- Fixed `GETDEL` prefixing (#1306)
|
||||
|
||||
## v2.1.2 (2023-03-02)
|
||||
|
||||
### Added
|
||||
- Added stream commands to `KeyPrefixProcessor` (#1051)
|
||||
- Added `ReplicationStrategy::$loadBalancing` option to disable replica reads (#1168)
|
||||
- Added support for `FCALL` and `FUNCTIONS` commands (#1049)
|
||||
- Added support for `PEXPIRETIME` command (#1031)
|
||||
- Added support for `EXPIRETIME` command (#1029)
|
||||
- Added support for `EVAL_RO` command (#1032)
|
||||
- Added support for `LCS` command (#1035)
|
||||
- Added support for `SORT_RO` command (#1044)
|
||||
- Added support for `SINTERCARD` command (#1027)
|
||||
- Added support for `EVALSHA_RO` command (#1034)
|
||||
- Added support for new arguments for `BITPOS` and `BITCOUNT` commands (#1045)
|
||||
- Added support for new arguments for `EXPIRE` and `EXPIREAT` commands (#1046)
|
||||
|
||||
### Bug Fixes
|
||||
- Fixed deprecated function call syntax
|
||||
|
||||
### Deprecated
|
||||
- Further deprecated phpiredis and webdis integration (#1179)
|
||||
|
||||
### Maintenance
|
||||
- Applied coding standards
|
||||
- Pass PHPStan level 2
|
||||
|
||||
## v2.1.1 (2023-01-17)
|
||||
|
||||
### Bug Fixes
|
||||
- Fix `@template` in `Predis\Client` (#1017)
|
||||
- Fix support options array in `ZINTERSTORE` and `ZUNIONSTORE` (#1018)
|
||||
|
||||
### Deprecated
|
||||
- Deprecated phpiredis and webdis connections
|
||||
|
||||
## v2.1.0 (2023-01-16)
|
||||
|
||||
### New Features
|
||||
- Implemented `GETEX` command (#872)
|
||||
- Implemented `GETDEL` command (#869)
|
||||
- Implemented `COPY` command (#866)
|
||||
- Implemented `FAILOVER` command (#875)
|
||||
- Implemented `LMOVE` command (#863)
|
||||
- Implemented `LMPOP` command (#1013)
|
||||
- Implemented `HRANDFIELD` command (#870)
|
||||
- Implemented `SMISMEMBER` command (#871)
|
||||
- Implemented `ZMPOP` command (#831)
|
||||
- Implemented `BLMOVE` command (#865)
|
||||
- Implemented `BLMPOP` command (#1015)
|
||||
- Implemented `BZMPOP` command (#833)
|
||||
- Implemented `BZPOPMIN` command (#862)
|
||||
- Implemented `BZPOPMAX` command (#864)
|
||||
- Implemented `ZUNION` command (#860)
|
||||
- Implemented `ZINTER` command (#859)
|
||||
- Implemented `ZINTERCARD` command (#861)
|
||||
- Implemented `ZRANGESTORE` command (#829)
|
||||
- Implemented `ZDIFFSTORE` command (#828)
|
||||
- Implemented `ZDIFF` command (#826)
|
||||
- Implemented `ZRANDMEMBER` command (#825)
|
||||
- Implemented `ZMSCORE` (#823)
|
||||
- Implemented `GEOSEARCH` command (#867)
|
||||
- Implemented `GEOSEARCHSTORE` command (#873)
|
||||
|
||||
### Bug Fixes
|
||||
- Added annotations to suppress PHP 8.1 return type deprecation warning (#810)
|
||||
|
||||
### Maintenance
|
||||
- Added mixin annotations for traits (#835)
|
||||
|
||||
## v2.0.3 (2022-10-11)
|
||||
|
||||
- Improved PHP 8.2 support
|
||||
- Call `is_resource()` before reading/writing
|
||||
- Added partial support for Redis Stream commands
|
||||
- Fixed Sentinel authentication issue
|
||||
|
||||
## v2.0.2 (2022-09-06)
|
||||
|
||||
- Fixed PHP 8.2 deprecation notice: Use of "static" in callables
|
||||
|
||||
## v2.0.1 (2022-09-04)
|
||||
|
||||
- Added retry interval to `RedisCluster` with a default of `10ms`
|
||||
- Avoid PHP 8.2 warning in `Connection\Parameters`
|
||||
- Fixed Sentinel reconnect issue in long-running PHP processes
|
||||
|
||||
## v2.0.0 (2022-06-08)
|
||||
|
||||
- Dropped support for PHP 7.1 and older
|
||||
|
||||
- Accepted values for some client options have changed, this is the new list of
|
||||
accepted values:
|
||||
|
||||
- `aggregate`: callable returning an aggregate connection.
|
||||
- `cluster`: string value (`predis`, `redis`), callable returning an aggregate
|
||||
connection.
|
||||
- `replication`: string value (`predis`, `sentinel`), callable returning an
|
||||
aggregate connection.
|
||||
- `commands`: command factory, named array mapping command IDs to PHP classes,
|
||||
callable returning a command factory or a named array.
|
||||
- `connections`: connection factory, callable object returning a connection
|
||||
factory, named array mapping URI schemes to PHP classes, string identifying
|
||||
a supported combination of configurations for the connection factory.
|
||||
- `prefix`: string value, command processor, callable.
|
||||
- `exceptions`: boolean.
|
||||
|
||||
Note that both the `cluster` and `replication` options now return a closure
|
||||
acting as initializer instead of an aggregate connection instance.
|
||||
|
||||
- The `connections` client option now accepts certain string values identifying
|
||||
certain combinations of configurations for the connection factory. Currently
|
||||
this is used to provide a short way to configure Predis to load our phpiredis
|
||||
based connection backends simply, accepted values are:
|
||||
|
||||
- `phpiredis-stream` maps `Phpiredis\Connection\PhpiredisStreamConnection` to
|
||||
`tcp`, `redis`, `unix` URI schemes.
|
||||
- `phpiredis-socket` maps `Phpiredis\Connection\PhpiredisSocketConnection` to
|
||||
`tcp`, `redis`, `unix` URI schemes.
|
||||
- `phpiredis-stream` is simply an alias of `phpiredis-stream`.
|
||||
|
||||
- Added the new `Predis\Cluster\Hash\PhpiredisCRC16` class using ext-phpiredis
|
||||
to speed-up the generation of the CRC16 hash of keys for redis-cluster. Predis
|
||||
automatically uses this class when ext-phpiredis is loaded, but it is possible
|
||||
to configure the hash generator using the new `crc16` client option (accepted
|
||||
values `predis`, `phpiredis` or an hash generator instance).
|
||||
|
||||
- Replication backends now use the `role` parameter instead of `alias` in order
|
||||
to distinguish the role of a connection. Accepted values are `master`, `slave`
|
||||
and, for redis-sentinel, `sentinel`. This led to a redesign of how connections
|
||||
can be retrieved from replication backends: the method getConnectionById() now
|
||||
retrieves a connection only by its ID (ip:port pair), to get a connection by
|
||||
its alias there is the new method getConnectionByAlias(). This method is not
|
||||
supported by the redis-sentinel backend due to its dynamic nature (connections
|
||||
are retrieved and initialized at runtime from sentinels) but it is possible to
|
||||
get a single connection from the pool by using its ID. It is also possible to
|
||||
retrieve a connection by role using the method getConnectionByRole().
|
||||
|
||||
- The concept of connection ID (ip:port pair) and connection alias (the `alias`
|
||||
parameter) in `Predis\Connection\Cluster\PredisCluster` has been separated.
|
||||
This change does not affect distribution and it is safe for existing clusters.
|
||||
|
||||
- Client option classes now live in the `Predis\Configuration\Option` namespace.
|
||||
|
||||
- Classes for Redis commands have been moved into the new `Predis\Command\Redis`
|
||||
namespace and each class name mirrors the respective Redis command ID.
|
||||
|
||||
- The concept of server profiles is gone, the library now uses a single command
|
||||
factory to create instances of commands classes. The `profile` option has been
|
||||
replaced by the `commands` option accepting `Predis\Command\FactoryInterface`
|
||||
to customize the underlying command factory. The default command factory class
|
||||
used by Predis is `Predis\Command\RedisFactory` and it still allows developers
|
||||
to define or override commands with their own implementations. In addition to
|
||||
that, `Predis\Command\RedisFactory` relies on a convention-over-configuration
|
||||
approach by looking for a suitable class with the same name as the command ID
|
||||
in the `Predis\Command\Redis` when the internal class map does not contain a
|
||||
class associated.
|
||||
|
||||
- The method `Predis\Client::getClientFor($connectionID)` has been replaced by
|
||||
`getClientBy($selector, $value, $callable = null)` which is more flexible as
|
||||
it is not limited to picking a connection from the underlying replication or
|
||||
cluster backend by ID, but allows users to specify a `$selector` that can be
|
||||
either `id` (the old behavior), `key`, `slot` or `command`. The client uses
|
||||
duck-typing instead of type-checking to verify that the underlying connection
|
||||
implements a method that matches the specified selector which means that some
|
||||
selectors may not be available to all kinds of connection backends.
|
||||
|
||||
- The method `Predis\Client::getConnectionById($connectionID)` has been removed.
|
||||
|
||||
- Changed the signature for the constructor of `Predis\Command\RawCommand`.
|
||||
|
||||
- The `Predis\Connection\Aggregate` namespace has been split into two separate
|
||||
namespaces for cluster backends (`Predis\Connection\Cluster`) and replication
|
||||
backends (`Predis\Connection\Replication`).
|
||||
|
||||
- The method `Predis\Connection\AggregateConnectionInterface::getConnection()`
|
||||
has been renamed to `getConnectionByCommand()`.
|
||||
|
||||
- The methods `switchToMaster()` and `switchToSlave()` have been promoted to be
|
||||
part of `Predis\Connection\Replication\ReplicationInterface` while the method
|
||||
`switchTo($connection)` has been removed from it.
|
||||
|
||||
- The method `Predis\Connection\Cluster\PredisCluster::executeCommandOnNodes()`
|
||||
has been removed as it is possible to achieve the same by iterating over the
|
||||
connection or, even better, over the client instance in order to execute the
|
||||
same command against all of the registered connections.
|
||||
|
||||
- The class `Predis\CommunicationException` now uses the correct default types
|
||||
for the `$message` (string) and `$code` (integer) parameters.
|
||||
|
||||
- The method `onConnectionError()` in `Predis\Connection\AbstractConnection`
|
||||
class now passes the second argument as an integer value `0` as its default
|
||||
value instead of `null`.
|
||||
|
||||
- Support Pub/Sub and Pipelines when using replication
|
||||
|
||||
- The class `Predis\Transaction\AbortedMultiExecException` now uses the correct
|
||||
default types for the `$code` (integer) parameter.
|
||||
|
||||
- __FIX__: using `strval` in `getScanOptions()` method, part of
|
||||
`Predis\Collection\Iterator\CursorBasedIterator` to make sure we retrieve the
|
||||
string value of `$this->match` and not passing `null` to `strlen()` function.
|
||||
|
||||
- __FIX__: the value returned from `getArgument()` in `isReadOperation()` method,
|
||||
part of `Predis\Replication\ReplicationStrategy` class, is checked to not pass
|
||||
`null` to `sha1` function.
|
||||
|
||||
- __FIX__: the value returned from `getArgument()` in `parseResponse()`method,
|
||||
part of `Predis\Command\Redis\SENTINEL` class, is checked to not pass `null`
|
||||
to `strtolower()` function.
|
||||
|
||||
## v2.0.0-beta.1 (2022-05-26)
|
||||
|
||||
Same as v2.0.0
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\Cluster\ClusterInterface;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
use Predis\Connection\NodeConnectionInterface;
|
||||
use Predis\NotSupportedException;
|
||||
use SplQueue;
|
||||
|
||||
/**
|
||||
* Command pipeline that does not throw exceptions on connection errors, but
|
||||
* returns the exception instances as the rest of the response elements.
|
||||
*/
|
||||
class ConnectionErrorProof extends Pipeline
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConnection()
|
||||
{
|
||||
return $this->getClient()->getConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function executePipeline(ConnectionInterface $connection, SplQueue $commands)
|
||||
{
|
||||
if ($connection instanceof NodeConnectionInterface) {
|
||||
return $this->executeSingleNode($connection, $commands);
|
||||
} elseif ($connection instanceof ClusterInterface) {
|
||||
return $this->executeCluster($connection, $commands);
|
||||
}
|
||||
$class = get_class($connection);
|
||||
|
||||
throw new NotSupportedException("The connection class '$class' is not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function executeSingleNode(NodeConnectionInterface $connection, SplQueue $commands)
|
||||
{
|
||||
$responses = [];
|
||||
$sizeOfPipe = count($commands);
|
||||
$buffer = '';
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$buffer .= $command->serializeCommand();
|
||||
}
|
||||
|
||||
try {
|
||||
$connection->write($buffer);
|
||||
} catch (CommunicationException $exception) {
|
||||
return array_fill(0, $sizeOfPipe, $exception);
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $sizeOfPipe; ++$i) {
|
||||
$command = $commands->dequeue();
|
||||
|
||||
try {
|
||||
$responses[$i] = $connection->readResponse($command);
|
||||
} catch (CommunicationException $exception) {
|
||||
$add = count($commands) - count($responses);
|
||||
$responses = array_merge($responses, array_fill(0, $add, $exception));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $responses;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function executeCluster(ClusterInterface $connection, SplQueue $commands)
|
||||
{
|
||||
$responses = [];
|
||||
$sizeOfPipe = count($commands);
|
||||
$exceptions = [];
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$nodeConnection = $connection->getConnectionByCommand($command);
|
||||
$nodeConnection->write($command->serializeCommand());
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $sizeOfPipe; ++$i) {
|
||||
$command = $commands->dequeue();
|
||||
|
||||
$cmdConnection = $connection->getConnectionByCommand($command);
|
||||
$connectionId = spl_object_id($cmdConnection);
|
||||
|
||||
if (isset($exceptions[$connectionId])) {
|
||||
$responses[$i] = $exceptions[$connectionId];
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$responses[$i] = $cmdConnection->readResponse($command);
|
||||
} catch (CommunicationException $exception) {
|
||||
$responses[$i] = $exception;
|
||||
$exceptions[$connectionId] = $exception;
|
||||
}
|
||||
}
|
||||
|
||||
return $responses;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\Redis\PING;
|
||||
use Predis\Connection\ConnectionException;
|
||||
use Predis\NotSupportedException;
|
||||
use PredisTestCase;
|
||||
|
||||
class ConnectionErrorProofTest extends PredisTestCase
|
||||
{
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testReturnsExceptionForEachCommandOnWriteFailureWithSingleConnection(): void
|
||||
{
|
||||
$buffer = (new PING())->serializeCommand() . (new PING())->serializeCommand() . (new PING())->serializeCommand();
|
||||
|
||||
$connection = $this->getMockConnection('tcp://127.0.0.1:7001');
|
||||
$exception = new ConnectionException($connection, 'Connection failed');
|
||||
|
||||
$connection
|
||||
->expects($this->once())
|
||||
->method('write')
|
||||
->with($buffer)
|
||||
->willThrowException($exception);
|
||||
$connection
|
||||
->expects($this->never())
|
||||
->method('readResponse');
|
||||
|
||||
$pipeline = new ConnectionErrorProof(new Client($connection));
|
||||
|
||||
$pipeline->ping();
|
||||
$pipeline->ping();
|
||||
$pipeline->ping();
|
||||
|
||||
$this->assertSame([$exception, $exception, $exception], $pipeline->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testReturnsExceptionOfEachFailedConnectionWithClusterConnection(): void
|
||||
{
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:7001');
|
||||
$exception1 = new ConnectionException($connection1, 'Connection to node 1 failed');
|
||||
$connection1
|
||||
->expects($this->exactly(2))
|
||||
->method('write');
|
||||
$connection1
|
||||
->expects($this->once())
|
||||
->method('readResponse')
|
||||
->willThrowException($exception1);
|
||||
|
||||
$connection2 = $this->getMockConnection('tcp://127.0.0.1:7002');
|
||||
$exception2 = new ConnectionException($connection2, 'Connection to node 2 failed');
|
||||
$connection2
|
||||
->expects($this->exactly(2))
|
||||
->method('write');
|
||||
$connection2
|
||||
->expects($this->once())
|
||||
->method('readResponse')
|
||||
->willThrowException($exception2);
|
||||
|
||||
$cluster = $this->getMockClusterConnection(['foo' => $connection1, 'bar' => $connection2]);
|
||||
|
||||
$pipeline = new ConnectionErrorProof(new Client($cluster));
|
||||
|
||||
$pipeline->get('foo');
|
||||
$pipeline->get('bar');
|
||||
$pipeline->get('foo');
|
||||
$pipeline->get('bar');
|
||||
|
||||
$this->assertSame([$exception1, $exception2, $exception1, $exception2], $pipeline->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testReadsResponsesFromHealthyConnectionsWhenOneFailsWithClusterConnection(): void
|
||||
{
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:7001');
|
||||
$exception = new ConnectionException($connection1, 'Connection to node 1 failed');
|
||||
$connection1
|
||||
->expects($this->exactly(2))
|
||||
->method('write');
|
||||
$connection1
|
||||
->expects($this->once())
|
||||
->method('readResponse')
|
||||
->willThrowException($exception);
|
||||
|
||||
$connection2 = $this->getMockConnection('tcp://127.0.0.1:7002');
|
||||
$connection2
|
||||
->expects($this->exactly(2))
|
||||
->method('write');
|
||||
$connection2
|
||||
->expects($this->exactly(2))
|
||||
->method('readResponse')
|
||||
->willReturnOnConsecutiveCalls('value1', 'value2');
|
||||
|
||||
$cluster = $this->getMockClusterConnection(['foo' => $connection1, 'bar' => $connection2]);
|
||||
|
||||
$pipeline = new ConnectionErrorProof(new Client($cluster));
|
||||
|
||||
$pipeline->get('foo');
|
||||
$pipeline->get('bar');
|
||||
$pipeline->get('foo');
|
||||
$pipeline->get('bar');
|
||||
|
||||
$this->assertSame([$exception, 'value1', $exception, 'value2'], $pipeline->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testThrowsExceptionOnUnsupportedConnection(): void
|
||||
{
|
||||
$this->expectException(NotSupportedException::class);
|
||||
$this->expectExceptionMessageMatches('/^The connection class \'.+\' is not supported\.$/');
|
||||
|
||||
$connection = $this->getMockBuilder('Predis\Connection\Replication\ReplicationInterface')->getMock();
|
||||
|
||||
$pipeline = new ConnectionErrorProof(new Client($connection));
|
||||
|
||||
$pipeline->ping();
|
||||
$pipeline->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mocked cluster connection routing commands by their first key.
|
||||
*
|
||||
* @param array $connectionsByKey Node connections indexed by key
|
||||
*
|
||||
* @return \PHPUnit\Framework\MockObject\MockObject|\Predis\Connection\Cluster\ClusterInterface
|
||||
*/
|
||||
private function getMockClusterConnection(array $connectionsByKey)
|
||||
{
|
||||
$cluster = $this->getMockBuilder('Predis\Connection\Cluster\ClusterInterface')->getMock();
|
||||
$cluster
|
||||
->expects($this->atLeastOnce())
|
||||
->method('getConnectionByCommand')
|
||||
->willReturnCallback(static function (CommandInterface $command) use ($connectionsByKey) {
|
||||
return $connectionsByKey[$command->getArgument(0)];
|
||||
});
|
||||
|
||||
return $cluster;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user