Commit Graph

148 Commits

Author SHA1 Message Date
Daniele Alessandri 6d6c970ae2 [tests] Replace deprecated TestCase::at().
The "at" matcher will be removed in PHPUnit 10 but it is not a bad thing
after all because it was cumbersome and error-prone.

Took the opportunity to improve some tests while converting them.
2020-09-01 14:03:19 +02:00
Daniele Alessandri c6f2ce4b83 [tests] Replace generic MockObject::will() with specialized methods. 2020-09-01 14:03:19 +02:00
Daniele Alessandri 36c9bb047e [tests] Start improving test suite.
- Make use of more typehints for function parameters
- Make use of typehints for function return values
- Use @var where needed to give proper hints to IDEs and avoid warnings
- Replace MockObject::setMethods() with addMethods() and onlyMethods()
- Rewording of some phpdocs
2020-09-01 13:58:14 +02:00
Daniele Alessandri c2ede30394 Merge remote-tracking branch 'github/pr/653' into main
Local branch v2.0-connections-phpiredisconfig
2020-08-31 10:54:40 +02:00
Daniele Alessandri 743be10f6e Merge remote-tracking branch 'github/pr/650' into main
Local branch v2.0-parameters-filterempty
2020-08-31 10:53:43 +02:00
Daniele Alessandri 7b86a7b54d Merge branch 'v1.1' into main 2020-08-30 23:40:36 +02:00
Daniele Alessandri b9ebe8a376 [tests] Fix mistype in TODO comments.
... and yay for copypasting it too!
2020-08-30 23:26:42 +02:00
Daniele Alessandri 87452e62d0 Fix authentication to support ACL with Redis 6.0.
When passing both "username" and "password" to connection parameters the
client now uses the extended AUTH command to support ACL authentication
with Redis 6.0.

The plain old authentication method is still supported like usual simply
by passing only "password" to connection parameters.
2020-08-29 14:11:55 +02:00
Daniele Alessandri 31baa9b241 Do not push AUTH and SELECT on empty "password" and "database".
NULL or zero-length string values passed to "password" and "database" in
the connection parameters list do not trigger spurious AUTH and SELECT
commands anymore when connecting to Redis.

Fixes #436.
2020-08-29 13:39:12 +02:00
Daniele Alessandri cc2a7657db Rework Predis\Command\FactoryInterface and related classes.
We have renamed most methods to drop the "command" suffix as it is quite
redundant. Due to this change and thanks to variadic methods introduced
with PHP 5.6 we took the opportunity to replace both "supportsCommand()"
and "supportsCommands()" with a single new method "supports()".

Added more stringent typehints for method arguments and typehints for
return values now that we do not need to support anything below PHP 7.2.
Also moved from using array() to [] in source code of class involved.
2020-08-28 14:23:12 +02:00
Daniele Alessandri accb030eb5 [tests] Minor adjustments for callable connection initalizers. 2020-08-26 00:57:03 +02:00
Daniele Alessandri 15eadb3426 Merge branch 'v1.1' into main 2020-08-25 16:07:06 +02:00
Daniele Alessandri b014d5de5a Filter NULL and zero-length string values for parameters.
Having NULL values or zero-length strings for connection parameters does
not make much sense and actually it proved to be an issue with certain
parameters like "password" where an empty string would trigger an AUTH
command with an empty password (and obviously Redis was not happy with
that). The main offenders were a few libraries and frameworks that kept
passing empty values for parameters such as "database" and "password"
even when users left them unconfigured. This fix should make things more
robust and avoid such occurrences in the future.

Related to PR #436 (rejected).
2020-08-25 12:20:53 +02:00
Daniele Alessandri 4b2b35202a [tests] Restore new message for failed assertion. 2020-08-18 16:12:45 +02:00
Daniele Alessandri c26909699b Merge remote-tracking branch 'github/pr/639' into main 2020-08-18 16:03:10 +02:00
Daniele Alessandri 33f5a0ec8c Merge branch 'stale-master' into main 2020-08-17 17:43:13 +02:00
Raza Mehdi 36a02cf807 Fix test. 2020-08-16 04:31:52 +05:00
Raza Mehdi 5edf443141 Fix tests. 2020-08-16 01:59:41 +05:00
Mark Fettig 39ff616e86 update sort command to be a write operation 2019-03-18 12:10:26 -04:00
Daniele Alessandri 89840412d5 [tests] Fix preassigned slots in cluster tests. 2016-06-18 21:53:49 +02:00
Daniele Alessandri 6ab10b2b70 [tests] Fix preassigned slots in cluster tests. 2016-06-18 21:51:10 +02:00
Daniele Alessandri 67c0fb8eb1 Separate id and alias in predis cluster (client-side sharding).
This change does not affect distribution but simply separates the two
concepts of connection ID (ip:port pair) and alias (value set via the
"alias" connection parameter), the method getConnectionByAlias() has
been added to reflect this change.

The method getConnectionBySlot() has also been added.
2016-06-18 17:12:20 +02:00
Daniele Alessandri 184d583895 Implement the concept of role for connections.
When using replication backends, now the role of a connection is not
defined by its alias but by the new connection parameter "role" that
can be set to "master", "slave" and (for redis-sentinel) "sentinel".

This also 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 still possible to get a single connection from the pool by
using its ID. It is also possible to retrive a connection by its role
using the method getConnectionByRole().

NOTE: the "role" parameter is an hint for the internals of aggregate
connection backends so it is still possible that the actual role of
a connection changes during the execution of a script (e.g. a slave
gets promoted to the role of master): in this case the parameters of
that connection will not be changed as they are immutable, but the
method getConnectionByRole() will return the appropriate connection.

Predis\Client::getClientBy() has been updated with the addition of
"role" and "alias" as supported selectors.
2016-06-18 15:32:53 +02:00
Daniele Alessandri 69e40dab2b Extract slot map logic to separate class.
In addition to that, the methods askSlotsMap() and buildSlotsMap() of
the redis-cluster connection backend have been renamed respectively
to askSlotMap() and buildSlotMap().
2016-06-17 22:18:38 +02:00
Daniele Alessandri 9d8adee1b1 Rename to getConnectionByCommand($command). 2016-06-16 10:39:44 +02:00
Pascal Hofmann d92f31dc66 Don't send AUTH and/or SELECT command after connecting to sentinels 2016-06-14 17:20:08 +02:00
Pascal Hofmann ce8b3fb683 Don't send AUTH and/or SELECT command after connecting to sentinels 2016-06-14 16:38:59 +02:00
Daniele Alessandri 2640062803 Use master for connect() when sentinel reports no slaves.
Fixes #342.
2016-06-13 16:32:45 +02:00
Daniele Alessandri a523cf7731 Use master for connect() when sentinel reports no slaves.
Fixes #342.
2016-06-13 15:51:23 +02:00
Daniele Alessandri eb1e686ff9 [tests] Change indentation of mock method expectations. 2016-06-10 11:08:26 +02:00
Daniele Alessandri 8b466d05df Get string of basic connection parameters from parameters class. 2016-06-08 18:36:35 +02:00
Daniele Alessandri c10479e238 Remove executeCommandOnNodes() from predis cluster backend.
It is still possible to achieve the same simply by iterating over the
connection or, even better, over the client instance.
2016-06-08 12:01:54 +02:00
Daniele Alessandri 1028599ac5 Split Predis\Connection\Aggregate namespace.
Now we have two namespaces for cluster and replication backends:

  - Predis\Connection\Cluster
  - Predis\Connection\Replication
2016-06-07 15:23:32 +02:00
Daniele Alessandri 62b421f20e Switch from server profiles to commands factory.
This change reduces some unnecessary complexity in the library, Redis
commands do not change much after all. Developers can still implement
their own commands factory, inject new commands or override existing
ones. The "profile" client options has been renamed to "commands" and
it accepts instances of Predis\Command\FactoryInterface.

The test suite checks at runtime the version of the running instance
of Redis for integration tests to adapt itself automatically.
2016-06-04 15:36:21 +02:00
Daniele Alessandri 1065edc8d1 Apply last round of CS fixes. 2016-06-01 22:31:06 +02:00
Daniele Alessandri 843ad23ea7 [tests] Move utility method into base test class. 2016-06-01 22:27:36 +02:00
Daniele Alessandri 922e56b480 Iterate only over connections mapped in slots map.
Iterating over Predis\Connection\Aggregate\RedisCluster returns all
the connections currently mapped in the slots map instead of just the
ones initialized in the pool.

When the slots map is retrieved from Redis (which by default is done
automatically) this allows to iterate over all of the current master
nodes of the cluster. When the underlying use of "CLUSTER SLOTS" is
disabled the iteration returns only connections with a slots range
associated in their parameters or initialized by `-MOVED` responses
to make the behaviour of the iteration consistent between the two
modes of operation.
2016-05-28 17:58:38 +02:00
Daniele Alessandri 5a0dfc3602 Fix parameters overriding for sentinels.
Different fix than PR #339 but thanks @phofmann-trust for spotting.
2016-05-28 15:53:23 +02:00
Daniele Alessandri 2d01a27e17 Fix fetching slots map from unreachable nodes.
When various nodes in the configuration are unreachable while trying
to send a command, we should attempt to contact a reachable node to
fetch an updated slots map up to $retryLimit times or until there are
no more servers in the pool before giving up.

It is possible that the slots map fetched from Redis contains stale
data and points to a dead server, this happens when the nodes still
have to agree that a master server is down before promoting a slave
to the role of master. In this case no further attempts to execute
the command are performed and an exception is thrown.

This still needs some more testing and will delay v1.0.4 a few days
past its scheduled release.
2016-05-27 14:30:07 +02:00
Daniele Alessandri 0477499418 Fix ROLE expectation for read commands with no slaves.
This commit fixes #337.
2016-05-25 15:56:33 +02:00
Daniele Alessandri 5b3a5bbef9 Run php-cs-fixer. 2016-05-21 15:46:58 +02:00
Daniele Alessandri 349a70a08a Merge branch 'v1.1-sentinel'
This merge resolves #131.
2016-05-21 15:30:22 +02:00
Daniele Alessandri c1de65c4ee Swap params order in redis-sentinel constructor. 2016-05-21 15:23:24 +02:00
Daniele Alessandri 05209e6e7d Switch to next slave on -LOADING error response.
This prevents an early failure of the command execution on the client
when one slave gets back online but is still loading the dataset from
disk (when this happens, Redis returns the -LOADING error response).

This commit fixes #280.
2016-05-20 21:59:40 +02:00
Daniele Alessandri d0cc7a5947 Try again on connection failure to node in cluster.
When the connection to a node in the cluster fails in the attempt to
execute a command, Predis now removes the failed connection from the
cluster pool and contacts a random node to ask for a fresh slots map
and tries to execute the command once again.

When the cluster is configured to have each master replicated to one
or more slaves, one the slaves is automatically promoted to the role
of master by redis-cluster with this change being reflected in the
output of CLUSTER SLOTS, so the next execution should run just fine.

Our current approach is relatively naive as CLUSTER SLOTS is executed
against a random master node, meaning that the client must open a new
connection and execute one more roundtrip only to fetch the new slots
map. For now it is enough, it is still better than having the client
fail when you actually have somes slaves in your redis-cluster setup,
but one improvement could consist in caching the list of slaves for
each master returned in the response of CLUSTER SLOTS so that when a
connection fails the client can try to guess which connection should
use for the next attempt.

This commit closes #173, closes #215, and closes #314.
2016-05-20 13:17:06 +02:00
Daniele Alessandri d6d307696a [tests] Add tests for redis-sentinel connection. 2016-05-19 22:15:55 +02:00
Daniele Alessandri 354e5e26da Improve handling of slots mapping via parameters.
When using redis-cluster it is now also possible to pass one slot or
non-contiguous ranges of slots via connection parameters in order to
improve the ability to pre-configure the slots map on the client.

Here is an example:

  $parameters = [
    'tcp://10.0.0.1:6379?slots=0-5460,5500-5600,11000',
    'tcp://10.0.0.2:6379?slots=5461-5499,5600-10921',
    'tcp://10.0.0.3:6379?slots=10922-10999,11001-16383',
  ];

This commit fixes #312 (props to @kenotr0n for the original PR).
2016-05-18 15:04:37 +02:00
Daniele Alessandri d55826f35c [tests] Fix tests from previous commit.
They did work, but I am not exactly sure why. Also added a missing
test for Predis\Connection\CompositeStreamConnection.
2016-05-17 20:06:30 +02:00
Daniele Alessandri 973e8592e3 Throw when command sent in connect() returns error.
Common failures are the use of SELECT with a database index outside
the bound of the configured number of databases in redis.conf or the
use of a wrong password for authentication with AUTH.

This resolves #322.
2016-05-17 19:15:21 +02:00
Daniele Alessandri 9f6759ca1c Implement discovery in basic replication.
Now the client can discover the whole replication configuration by
asking to one of the servers (master has the precedence) using the
INFO REPLICATION command. This is obviously a best-effort fallback
and there is no strong guarantee about reliability and efficiency.

By enabling auto-discovery, the client automates this process when
the execution of a command fails because one of the target servers
is unreachable. The replication connection requires an instance of
connection factory associated to it in order to be able to create
new connections on the fly.

It is possible to enable the auto-discovery procedure easily via
client options:

  $client = new Predis\Client($servers, [
    'replication' => true,
    'autodiscovery' => true,
  ]);
2016-05-17 14:24:52 +02:00