Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Cache] Add ability to configure predis client.#28175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
jralph wants to merge1 commit intosymfony:masterfromjralph:predis-client-config

Conversation

@jralph
Copy link

@jralphjralph commentedAug 9, 2018
edited
Loading

QA
Branch?master
Bug fix?no
New feature?yes
BC breaks?no
Deprecations?no
Tests pass?yes
Fixed tickets
LicenseMIT
Doc PR

When usingpredis/predis, there is currently no way to set any options as the 2nd parameter in thePredis\Client constructor. This merge allows you to define these options with apredis_options query parameter in the dsn.

Example:

default_redis_provider: 'redis://localhost:6379?predis_options[cluster]=redis&predis_options[profile]=2.8'

@jralphjralphforce-pushed thepredis-client-config branch 2 times, most recently fromeffe292 to05c319fCompareAugust 9, 2018 13:14
@jralphjralph changed the titlePredis client config[Cache] Add ability to configure predis client.Aug 9, 2018
@nicolas-grekas
Copy link
Member

Hello, thanks for the PR. Here is the options reference:
https://github.com/nrk/predis/wiki/Client-Options

To understand better, which options are useful in your case?
E.g. "profile" is not needed in the context of a cache pool.
For "cluster", is this the canonical way to connect to a cluster? From the doc "redis" is not a legal value, unless I missed something. I don't know predis well so I'd be happy to have more details. Thanks.

@jralph
Copy link
Author

jralph commentedAug 9, 2018
edited
Loading

Hi@nicolas-grekas,

No problem, I'd be happy to provide some more info! The predis docs are a little off in the wiki. The readme.md specifies there are 3 options, the one mentioned in the wiki, plus eitherredis orpredis. Theredis option specifies that predis should let the redis servers manage the clustering themselves (for clustered redis). If this is set aspredis or a callable, this is for client based redis clustering where you just give it a bunch of non-connected redis servers the client handles the sharding/clustering/replication and so on.

See:https://github.com/nrk/predis#client-configuration
See:https://redis.io/topics/cluster-tutorial

Theprofile option was only included as an example of passing multiple options to the client.

@nicolas-grekas
Copy link
Member

Thanks for the links.

Right now, Predis is skipped when ext-redis is installed.
When one setspredis_options, I suppose one expects Predis to be used.
I'd suggest to throw an exception when that's not the case.

@jralph
Copy link
Author

jralph commentedAug 14, 2018
edited
Loading

Do you reckon it would be better to throw an exception in that case, or to enforce the use of predis instead? This could be could be done expanding uppon the if statement that checks for the existence of ext-redis. It could check for ext-redis as well as predis options and default to predis if they are present.

It's possible someone could have ext-redis available, but would prefer to use predis for the clustering capability. But still use ext-redis for other redis instances that are not clustered. Allowing thepredis_options to force predis could work out better in this use case.

@nicolas-grekas
Copy link
Member

Setting theclass option toRedisCluster is another way to connect to a cluster directly with the extension.
About your question, I'm not sure. I think I would prefer automatic configuration: when a predis option is used, we could forceclass accordingly, and fail with a clear error message when the package is not installed. WDYT ?

@jralphjralphforce-pushed thepredis-client-config branch 3 times, most recently from0f08f1b to2fe2f53CompareAugust 15, 2018 11:01
@jralph
Copy link
Author

jralph commentedAug 15, 2018
edited
Loading

I haven't got much experience with the redis extension, does theRedisCluster class extend theRedis class?

I agree, I think having the code work out what you're trying to use and fail on an invalid configuration setup is ideal.

I've updated the code to reflect the more automated configuration approach as well as added tests to check this config.

If a predis option is specified and predis is not available it will throw aCacheException. If a predis option is specified and a custom class is specified, it will check that the custom class is an instance of\Predis\Client and throw anInvalidArgumentException if not. What are your thoughts on this?

Copy link
Member

@nicolas-grekasnicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

some more comment to help move forward.
LGTM afterwards, thanks.

$params +=$options +self::$defaultConnectionOptions;
if (null ===$params['class'] && !\extension_loaded('redis') && !class_exists(\Predis\Client::class)) {
thrownewCacheException(sprintf('Cannot find the "redis" extension, and "predis/predis" is not installed: %s',$dsn));
}elseif (isset($params['predis_options']) && !class_exists(\Predis\Client::class)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

we prefer replacing such "elseif" by an "if" (can be done when the previous "if" break the code flow, with throw or return typically. (same below)

if (null ===$params['class'] && !\extension_loaded('redis') && !class_exists(\Predis\Client::class)) {
thrownewCacheException(sprintf('Cannot find the "redis" extension, and "predis/predis" is not installed: %s',$dsn));
}elseif (isset($params['predis_options']) && !class_exists(\Predis\Client::class)) {
thrownewCacheException(sprintf('DSN contains "predis_options" and "predis/predis" is not installed: %s',$dsn));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The option can come from the $options argument, so the message should not tell about the DSN I'd say.
What about `Invalid connection option: "predis_options" provided but "predis/predis" is not installed.', $dsn));

thrownewCacheException(sprintf('DSN contains "predis_options" and "predis/predis" is not installed: %s',$dsn));
}elseif (isset($params['predis_options']) || !\extension_loaded('redis')) {
if (null !==$params['class'] && !is_a($params['class'], \Predis\Client::class,true)) {
thrownewInvalidArgumentException(sprintf('Cannot find the "redis" extension and expected an instance of %s, instead got: %s', \Predis\Client::class,$params['class']));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

the message is confusing: when the extensionis installed, we should tell otherwise.

thrownewInvalidArgumentException(sprintf('Cannot find the "redis" extension and expected an instance of %s, instead got: %s', \Predis\Client::class,$params['class']));
}

$class =null ===$params['class'] ? \Predis\Client::class :$params['class'];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

$class = $params['class'] ?? \Predis\Client::class; (same below)

$params['password'] =$auth;
$redis =new$class((newFactory())->create($params));

$predisOptions =false !==isset($params['predis_options']) &&true ===\is_array($params['predis_options']) ?$params['predis_options'] :array();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

no need for the boolean comparisons:
$predisOptions = isset($params['predis_options']) && \is_array($params['predis_options']) ? $params['predis_options'] : array();
but shouldn't we throw when predis_options is not an array?

@jralphjralphforce-pushed thepredis-client-config branch 4 times, most recently from5794698 to1ac9b3eCompareAugust 16, 2018 11:58
@jralph
Copy link
Author

jralph commentedAug 16, 2018
edited
Loading

Great, I've made those suggested changes now and cleaned up a few of the exception messages a bit!

* added sub-second expiry accuracy for backends that support it
* added support for phpredis 4`compression` and`tcp_keepalive` options
* added automatic table creation when using Doctrine DBAL with PDO-based backends
* added support for a`predis_options` query parameter array in the redis dsn.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

DSN


$predisOptions =$params['predis_options'] ??array();

if (!\is_array($predisOptions)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We are not doing this kind of checks anywhere in the code base, not sure if we want it here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

What would you recommend instead? If we don't check and throw an exception predis will, I would imagine this would suffice?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Letting predis handle the situation seems better.

@jralph
Copy link
Author

jralph commentedAug 20, 2018
edited
Loading

I've made the suggested changes in the code and theCHANGELOG.md file now.

Was the line doing$predisOptions = $params['predis_options'] ?? array(); something you wanted changed as well, or is that part ok?

@jralphjralphforce-pushed thepredis-client-config branch 2 times, most recently fromdcff981 toa260177CompareAugust 20, 2018 14:00
When the predis driver is created, there is no current way toconfigure the predis client options (such as setting the clustermode to redis). This merge allows you to add a predis_optionsparameter to the dsn to allow configuration of options.
@jralph
Copy link
Author

I'm not sure what's caused the tests to fail for travic-ci there. Any ideas? Seems to be something to do with the Process component?

@jralph
Copy link
Author

jralph commentedSep 10, 2018
edited
Loading

@fabpot Were the changes made suitable for what you mentioned?

@nicolas-grekas
Copy link
Member

See proposal in#28300 (comment)

@jralph
Copy link
Author

jralph commentedSep 13, 2018
edited
Loading

Having done some more debugging on this, I do not believe my merge is yet complete so please do not accept it yet.

There is an issue where passing in a single host to predis causes it to ignore the clustering setup completely, using the default stream connection instead of creating a cluster. (For example, aws elasticache redis clusters that have a single entry endpoint.)

I'm not yet quite sure on how to approach this, possibly if clustering is expected, to pass in an array of hosts (an array of 1 host works), instead of a single string to the factory.

It also appears the predis factory does not support creating a redis cluster connection.

The current tests pass only because when calling the code to get thecluster option actually causes the creation of a cluster connection, giving a false positive. When passing in a dsn as a single string and not an array of dsn's, redis clustering is never used.

I think this changes the scope of changes required to theRedisTrait to get clustering to work, it may be that#28300 provides a better solution to go with overall instead of my attempt here.

@nicolas-grekas
Copy link
Member

Closing in favor of#28713
Please review/test this PR and see if this works for you.
It'd be awesome if you could contribute some doc for it :)

fabpot added a commit that referenced this pull requestOct 10, 2018
… via DSN (nicolas-grekas)This PR was merged into the 4.2-dev branch.Discussion----------[Cache] added support for connecting to Redis clusters via DSN| Q             | A| ------------- | ---| Branch?       | master| Bug fix?      | no| New feature?  | yes| BC breaks?    | no| Deprecations? | no| Tests pass?   | yes| Fixed tickets | -| License       | MIT| Doc PR        | -Replaces#28300 and#28175This PR allows configuring a cluster of Redis servers using all available options of either the phpredis extension or the Predis package:- the `redis_cluster=0/1` boolean option configures whether the client should use the Redis cluster protocol;- several hosts can be provided using a syntax very similar to#28598, enabling consistent hashing distribution of keys;- `failover=error/distribute/slaves` can be set to direct reads at slave servers;- extra options are passed as is to the driver (e.g. `profile=2.8`)- Predis per-server settings are also possible, using e.g. `host[localhost][alias]=foo` in the query string, or `host[localhost]=alias%3Dfoo` (ie PHP query arrays or urlencoded key/value pairs)Commits-------a42e877 [Cache] added support for connecting to Redis clusters via DSN
@nicolas-grekasnicolas-grekas modified the milestones:next,4.2Nov 1, 2018
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@fabpotfabpotfabpot requested changes

@nicolas-grekasnicolas-grekasnicolas-grekas approved these changes

Assignees

No one assigned

Projects

None yet

Milestone

4.2

Development

Successfully merging this pull request may close these issues.

4 participants

@jralph@nicolas-grekas@fabpot@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp