Coder Social home page Coder Social logo

reactphp-redis's Introduction

clue/reactphp-redis

CI status code coverage PHPStan level installs on Packagist

Async Redis client implementation, built on top of ReactPHP.

Development version: This branch contains the code for the upcoming 3.0 release. For the code of the current stable 2.x release, check out the 2.x branch.

The upcoming 3.0 release will be the way forward for this package. However, we will still actively support 2.x for those not yet on the latest version. See also installation instructions for more details.

Redis is an open source, advanced, in-memory key-value database. It offers a set of simple, atomic operations in order to work with its primitive data types. Its lightweight design and fast operation makes it an ideal candidate for modern application stacks. This library provides you a simple API to work with your Redis database from within PHP. It enables you to set and query its data or use its PubSub topics to react to incoming events.

  • Async execution of Commands - Send any number of commands to Redis in parallel (automatic pipeline) and process their responses as soon as results come in. The Promise-based design provides a sane interface to working with async responses.
  • Event-driven core - Register your event handler callbacks to react to incoming events, such as an incoming PubSub message event.
  • Lightweight, SOLID design - Provides a thin abstraction that is just good enough and does not get in your way. Future or custom commands and events require no changes to be supported.
  • Good test coverage - Comes with an automated tests suite and is regularly tested against versions as old as Redis v2.6 and newer.

Table of Contents

Support us

We invest a lot of time developing, maintaining and updating our awesome open-source projects. You can help us sustain this high-quality of our work by becoming a sponsor on GitHub. Sponsors get numerous benefits in return, see our sponsoring page for details.

Let's take these projects to the next level together! 🚀

Quickstart example

Once installed, you can use the following code to connect to your local Redis server and send some requests:

<?php

require __DIR__ . '/vendor/autoload.php';

$redis = new Clue\React\Redis\RedisClient('localhost:6379');

$redis->set('greeting', 'Hello world');
$redis->append('greeting', '!');

$redis->get('greeting')->then(function (string $greeting) {
    // Hello world!
    echo $greeting . PHP_EOL;
});

$redis->incr('invocation')->then(function (int $n) {
    echo 'This is invocation #' . $n . PHP_EOL;
});

See also the examples.

Usage

Commands

Most importantly, this project provides a RedisClient instance that can be used to invoke all Redis commands (such as GET, SET, etc.).

$redis = new Clue\React\Redis\RedisClient('localhost:6379');

$redis->get($key);
$redis->set($key, $value);
$redis->exists($key);
$redis->expire($key, $seconds);
$redis->mget($key1, $key2, $key3);

$redis->multi();
$redis->exec();

$redis->publish($channel, $payload);
$redis->subscribe($channel);

$redis->ping();
$redis->select($database);

// many more…

Each method call matches the respective Redis command. For example, the $redis->get() method will invoke the GET command.

All Redis commands are automatically available as public methods via the magic __call() method. Listing all available commands is out of scope here, please refer to the Redis command reference.

Any arguments passed to the method call will be forwarded as command arguments. For example, the $redis->set('name', 'Alice') call will perform the equivalent of a SET name Alice command. It's safe to pass integer arguments where applicable (for example $redis->expire($key, 60)), but internally Redis requires all arguments to always be coerced to string values.

Each of these commands supports async operation and returns a Promise that eventually fulfills with its results on success or rejects with an Exception on error. See also the following section about promises for more details.

Promises

Sending commands is async (non-blocking), so you can actually send multiple commands in parallel. Redis will respond to each command request with a response message, pending commands will be pipelined automatically.

Sending commands uses a Promise-based interface that makes it easy to react to when a command is completed (i.e. either successfully fulfilled or rejected with an error):

$redis->get($key)->then(function (?string $value) {
    var_dump($value);
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

PubSub

This library is commonly used to efficiently transport messages using Redis' Pub/Sub (Publish/Subscribe) channels. For instance, this can be used to distribute single messages to a larger number of subscribers (think horizontal scaling for chat-like applications) or as an efficient message transport in distributed systems (microservice architecture).

The PUBLISH command can be used to send a message to all clients currently subscribed to a given channel:

$channel = 'user';
$message = json_encode(['id' => 10]);
$redis->publish($channel, $message);

The SUBSCRIBE command can be used to subscribe to a channel and then receive incoming PubSub message events:

$channel = 'user';
$redis->subscribe($channel);

$redis->on('message', function (string $channel, string $payload) {
    // pubsub message received on given $channel
    var_dump($channel, json_decode($payload));
});

Likewise, you can use the same client connection to subscribe to multiple channels by simply executing this command multiple times:

$redis->subscribe('user.register');
$redis->subscribe('user.join');
$redis->subscribe('user.leave');

Similarly, the PSUBSCRIBE command can be used to subscribe to all channels matching a given pattern and then receive all incoming PubSub messages with the pmessage event:

$pattern = 'user.*';
$redis->psubscribe($pattern);

$redis->on('pmessage', function (string $pattern, string $channel, string $payload) {
    // pubsub message received matching given $pattern
    var_dump($channel, json_decode($payload));
});

Once you're in a subscribed state, Redis no longer allows executing any other commands on the same client connection. This is commonly worked around by simply creating a second client connection and dedicating one client connection solely for PubSub subscriptions and the other for all other commands.

The UNSUBSCRIBE command and PUNSUBSCRIBE command can be used to unsubscribe from active subscriptions if you're no longer interested in receiving any further events for the given channel and pattern subscriptions respectively:

$redis->subscribe('user');

Loop::addTimer(60.0, function () use ($redis) {
    $redis->unsubscribe('user');
});

Likewise, once you've unsubscribed the last channel and pattern, the client connection is no longer in a subscribed state and you can issue any other command over this client connection again.

Each of the above methods follows normal request-response semantics and return a Promise to await successful subscriptions. Note that while Redis allows a variable number of arguments for each of these commands, this library is currently limited to single arguments for each of these methods in order to match exactly one response to each command request. As an alternative, the methods can simply be invoked multiple times with one argument each.

Additionally, can listen for the following PubSub events to get notifications about subscribed/unsubscribed channels and patterns:

$redis->on('subscribe', function (string $channel, int $total) {
    // subscribed to given $channel
});
$redis->on('psubscribe', function (string $pattern, int $total) {
    // subscribed to matching given $pattern
});
$redis->on('unsubscribe', function (string $channel, int $total) {
    // unsubscribed from given $channel
});
$redis->on('punsubscribe', function (string $pattern, int $total) {
    // unsubscribed from matching given $pattern
});

When the underlying connection is lost, the unsubscribe and punsubscribe events will be invoked automatically. This gives you control over re-subscribing to the channels and patterns as appropriate.

API

RedisClient

The RedisClient is responsible for exchanging messages with your Redis server and keeps track of pending commands.

$redis = new Clue\React\Redis\RedisClient('localhost:6379');

$redis->incr('hello');

Besides defining a few methods, this interface also implements the EventEmitterInterface which allows you to react to certain events as documented below.

Internally, this class creates the underlying connection to Redis only on demand once the first request is invoked on this instance and will queue all outstanding requests until the underlying connection is ready. This underlying connection will be reused for all requests until it is closed. By default, idle connections will be held open for 1ms (0.001s) when not used. The next request will either reuse the existing connection or will automatically create a new underlying connection if this idle time is expired.

From a consumer side this means that you can start sending commands to the database right away while the underlying connection may still be outstanding. Because creating this underlying connection may take some time, it will enqueue all outstanding commands and will ensure that all commands will be executed in correct order once the connection is ready.

If the underlying database connection fails, it will reject all outstanding commands and will return to the initial "idle" state. This means that you can keep sending additional commands at a later time which will again try to open a new underlying connection. Note that this may require special care if you're using transactions (MULTI/EXEC) that are kept open for longer than the idle period.

While using PubSub channels (see SUBSCRIBE and PSUBSCRIBE commands), this client will never reach an "idle" state and will keep pending forever (or until the underlying database connection is lost). Additionally, if the underlying database connection drops, it will automatically send the appropriate unsubscribe and punsubscribe events for all currently active channel and pattern subscriptions. This allows you to react to these events and restore your subscriptions by creating a new underlying connection repeating the above commands again.

Note that creating the underlying connection will be deferred until the first request is invoked. Accordingly, any eventual connection issues will be detected once this instance is first used. You can use the end() method to ensure that the connection will be soft-closed and no further commands can be enqueued. Similarly, calling end() on this instance when not currently connected will succeed immediately and will not have to wait for an actual underlying connection.

__construct()

The new RedisClient(string $url, ConnectorInterface $connector = null, LoopInterface $loop = null) constructor can be used to create a new RedisClient instance.

The $url can be given in the standard form [redis[s]://][:auth@]host[:port][/db]. You can omit the URI scheme and port if you're connecting to the default port 6379:

// both are equivalent due to defaults being applied
$redis = new Clue\React\Redis\RedisClient('localhost');
$redis = new Clue\React\Redis\RedisClient('redis://localhost:6379');

Redis supports password-based authentication (AUTH command). Note that Redis' authentication mechanism does not employ a username, so you can pass the password h@llo URL-encoded (percent-encoded) as part of the URI like this:

// all forms are equivalent
$redis = new Clue\React\Redis\RedisClient('redis://:h%40llo@localhost');
$redis = new Clue\React\Redis\RedisClient('redis://ignored:h%40llo@localhost');
$redis = new Clue\React\Redis\RedisClient('redis://localhost?password=h%40llo');

You can optionally include a path that will be used to select (SELECT command) the right database:

// both forms are equivalent
$redis = new Clue\React\Redis\RedisClient('redis://localhost/2');
$redis = new Clue\React\Redis\RedisClient('redis://localhost?db=2');

You can use the standard rediss:// URI scheme if you're using a secure TLS proxy in front of Redis:

$redis = new Clue\React\Redis\RedisClient('rediss://redis.example.com:6340');

You can use the redis+unix:// URI scheme if your Redis instance is listening on a Unix domain socket (UDS) path:

$redis = new Clue\React\Redis\RedisClient('redis+unix:///tmp/redis.sock');

// the URI MAY contain `password` and `db` query parameters as seen above
$redis = new Clue\React\Redis\RedisClient('redis+unix:///tmp/redis.sock?password=secret&db=2');

// the URI MAY contain authentication details as userinfo as seen above
// should be used with care, also note that database can not be passed as path
$redis = new Clue\React\Redis\RedisClient('redis+unix://:secret@/tmp/redis.sock');

This method respects PHP's default_socket_timeout setting (default 60s) as a timeout for establishing the underlying connection and waiting for successful authentication. You can explicitly pass a custom timeout value in seconds (or use a negative number to not apply a timeout) like this:

$redis = new Clue\React\Redis\RedisClient('localhost?timeout=0.5');

By default, idle connections will be held open for 1ms (0.001s) when not used. The next request will either reuse the existing connection or will automatically create a new underlying connection if this idle time is expired. This ensures you always get a "fresh" connection and as such should not be confused with a "keepalive" or "heartbeat" mechanism, as this will not actively try to probe the connection. You can explicitly pass a custom idle timeout value in seconds (or use a negative number to not apply a timeout) like this:

$redis = new Clue\React\Redis\RedisClient('localhost?idle=10.0');

If you need custom DNS, proxy or TLS settings, you can explicitly pass a custom instance of the ConnectorInterface:

$connector = new React\Socket\Connector([
    'dns' => '127.0.0.1',
    'tcp' => [
        'bindto' => '192.168.10.1:0'
    ],
    'tls' => [
        'verify_peer' => false,
        'verify_peer_name' => false
    ]
]);

$redis = new Clue\React\Redis\RedisClient('localhost', $connector);

__call()

The __call(string $name, string[] $args): PromiseInterface<mixed> method can be used to invoke the given command.

This is a magic method that will be invoked when calling any Redis command on this instance. Each method call matches the respective Redis command. For example, the $redis->get() method will invoke the GET command.

$redis->get($key)->then(function (?string $value) {
    var_dump($value);
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

All Redis commands are automatically available as public methods via this magic __call() method. Listing all available commands is out of scope here, please refer to the Redis command reference.

Any arguments passed to the method call will be forwarded as command arguments. For example, the $redis->set('name', 'Alice') call will perform the equivalent of a SET name Alice command. It's safe to pass integer arguments where applicable (for example $redis->expire($key, 60)), but internally Redis requires all arguments to always be coerced to string values.

Each of these commands supports async operation and returns a Promise that eventually fulfills with its results on success or rejects with an Exception on error. See also promises for more details.

end()

The end():void method can be used to soft-close the Redis connection once all pending commands are completed.

close()

The close():void method can be used to force-close the Redis connection and reject all pending commands.

error event

The error event will be emitted once a fatal error occurs, such as when the client connection is lost or is invalid. The event receives a single Exception argument for the error instance.

$redis->on('error', function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

This event will only be triggered for fatal errors and will be followed by closing the client connection. It is not to be confused with "soft" errors caused by invalid commands.

close event

The close event will be emitted once the client connection closes (terminates).

$redis->on('close', function () {
    echo 'Connection closed' . PHP_EOL;
});

See also the close() method.

Install

The recommended way to install this library is through Composer. New to Composer?

Once released, this project will follow SemVer. At the moment, this will install the latest development version:

composer require clue/redis-react:^3@dev

See also the CHANGELOG for details about version upgrades.

This project aims to run on any platform and thus does not require any PHP extensions and supports running on PHP 7.1 through current PHP 8+. It's highly recommended to use the latest supported PHP version for this project.

We're committed to providing long-term support (LTS) options and to provide a smooth upgrade path. You may target multiple versions at the same time to support a wider range of PHP versions like this:

composer require "clue/redis-react:^3@dev || ^2"

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

composer install

To run the test suite, go to the project root and run:

vendor/bin/phpunit

The test suite is set up to always ensure 100% code coverage across all supported environments. If you have the Xdebug extension installed, you can also generate a code coverage report locally like this:

XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text

The test suite contains both unit tests and functional integration tests. The functional tests require access to a running Redis server instance and will be skipped by default.

If you don't have access to a running Redis server, you can also use a temporary Redis Docker image:

docker run --net=host redis

To now run the functional tests, you need to supply your login details in an environment variable like this:

REDIS_URI=localhost:6379 vendor/bin/phpunit

On top of this, we use PHPStan on max level to ensure type safety across the project:

vendor/bin/phpstan

License

This project is released under the permissive MIT license.

Did you know that I offer custom development services and issuing invoices for sponsorships of releases and for contributions? Contact me (@clue) for details.

reactphp-redis's People

Contributors

clue avatar dinooo13 avatar iwai avatar kitsunde avatar nyholm avatar paulrotmann avatar simonfrings avatar wyrihaximus avatar yadaiio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactphp-redis's Issues

Consistent namespace

Use Clue\React\Redis namespace in order to be consistent with my remaining projects based on React PHP.

Extending StreamingClient without rewriting Factory

Hello!

How would one extend StreamingClient and use extended class without rewriting the whole Factory class?

It seems to be easy to implement the Factory in such way that it would create a custom (extended) StreamingClient by just providing the class to use (https://github.com/clue/reactphp-redis/blob/master/src/Factory.php#L69) somewhere in the Factory.

Maybe something like:

$factory->setClientClass(...);

Which would override the default Clue\React\Redis\StreamingClient.

That way we can easily use Factory and build upon (extend) StreamingClient. It just seems such a waste to rewrite (and maintain) Factory class just to change the returned StreamingClient object.

I can make PR for this if the idea is feasible.

Thanks for great software!

Cheers,
Dejan

Question : Async transaction

Is clue/php-redis-react safe for redis transactions?

$client->multi();
$client->incr('foo');
$client->incr('bar');
$client->exec();

I want to know as clue/php-redis-react have async behavior . Do you handle transaction correctly?

How to stop the loop without closing the connections

Is there any way to stop the react event loop and keeping the redis connection open? I just want to use this package to send a command to multiple instances of redis at once and wait for all the responses inside a laravel application. I don't think it is a good idea to add extra overhead to reconnect everytime I need to do that.

LazyClient: no error messages

Suppose I have a redis process running on a standard port and in my code I make a mistake by incorrectly specifying the port. How do I know about the error?

<?php

$loader = require __DIR__ . '/vendor/autoload.php';

use \Clue\React\Redis\Factory;
use \Clue\React\Redis\Client;

$loop = React\EventLoop\Factory::create();

$factory = new Factory($loop);

$client = $factory->createLazyClient('redis://127.0.0.1:9006');

$client->on('error', function (Exception $e) {
    echo "Error: " . $e . PHP_EOL;
});

$client->on('close', function () {
    echo "Connection closed" . PHP_EOL;
});

$client->set('qwe', 1234)->then(function ($r) use ($loop) {
    $loop->stop();
});

$loop->run();

Improve documentation for MULTI / EXEC

I mostly just want to clarify how to use MULTI / EXEC in an async/promise context.

How should code be structured when doing MULTI?

$client->multi()->then(function() use ($client) {
    $client->get('a', 'b');
    $client->get('c', 'd');
    return $client->exec()->then(function($data) {
        return doSomething($data);
    });
});

or...

$client->multi();
$client->get('a', 'b');
$client->get('c', 'd');
return $client->exec()->then(function($data) {
	return doSomething($data);
});

etc.

Examples needed: pipeline()

this is actually not an issue, but more of a question, which I can't get answered online.
I have whole bunch of requests, which I would love to put into pipeline.
As each client implements pipeline their own way, I just don't know, how to do it for my code.
Would you mind giving me an example, please?

take care and keep up the good work :)
Saso

Expire bug

I have a use case that only use SET and GET commands in redis , Always I use EX option in SET command

SET mykey "Hello" EX 10
GET mykey

I see that some keys in redis has TTL = -1 , and GET mykey returns value of key

I think there is a bug in clue/php-redis-react that don't send additional option to redis sometimes

From https://redis.io/commands/expire I know that

The timeout will only be cleared by commands that delete or overwrite the contents of the key

But as I told before I just overwrite the contents of the key by SET and always use EX option so all keys must be expired

In PHP script I use the following command to SET a value to a key

$client->set('mykey', 'Hello','EX',10);

Additional events for non-request-reply messages

This library currently focuses on the usual Request-Reply pattern used by most of redis' commands. Some commands, however, can reply with several messages per request, notably (P|UN)SUBSCRIBE, WATCH etc.

Removing the requirement for matching replies to requests should be fairly easy. But we still want that kind of functionality for normal requests, so we have to make sure to properly switch states. E.g. once we're in subscription state, additional requests such as GET/SET are invalid and will lead to an error.

Also refs #1.

Options

How can I set command options?
for example for SET command according to https://redis.io/commands/set we have these options

  • EX seconds -- Set the specified expire time, in seconds.
  • PX milliseconds -- Set the specified expire time, in milliseconds.
  • NX -- Only set the key if it does not already exist.
  • XX -- Only set the key if it already exist.

Support redis:// URI scheme and ignore username for AUTH

In the Factories parseUrl method, you are generating the auth param by combining the username and password. Redis as far as I am aware has no concept of users. A lot of connection strings just specify one because otherwise the password won't be parsed correctly by most tools. Ex: redis://anything:password@host:port.

It is an easy fix:

$auth = null;
if (isset($parts['user'])) {
    $auth = $parts['user'];
}
if (isset($parts['pass'])) {
    $auth .= ':' . $parts['pass'];
}
if ($auth !== null) {
    $parts['auth'] = $auth;
}

change to

if (isset($parts['pass'])) {
    $parts['auth'] = $parts['pass'];
}

I also am going to mention that redis:// is also a valid schema:

if ($parts === false || !isset($parts['host']) || $parts['scheme'] !== 'tcp') {
    throw new InvalidArgumentException('Given URL can not be parsed');
}

changes to

$validSchemes = array('redis', 'tcp');
if ($parts === false || !isset($parts['host']) || !in_array($parts['scheme'], $validSchemes)) {
    throw new InvalidArgumentException('Given URL can not be parsed');
}

Sentinel

I want to know , is clue/php-redis-react support Sentinel ? If not can you please implement it?

Switch to use React / Socket, instead of Socket Client

Hi Clue

Due to the major changes in react (which you have contributed to), I am sadly no longer able to use the package. The main reason is that this package depends on the React / SocketClient package.

Can you please update the package's dependencies and release it as version 2.x (important so that you don't break compatibility for those that use version 1.x)

Don't work with php7 & event

#php version:7.0.18
event extension : 2.3.0

require_once __DIR__ . '/../../vendor/autoload.php';

$loop = React\EventLoop\Factory::create();
$factory = new Factory($loop);
$factory->createClient("127.0.0.1:6379")->then(function (Client $client) use ($loop) {
    echo '# connected! Entering interactive mode, hit CTRL-D to quit' . PHP_EOL;

    $client->on('data', function (ModelInterface $data) {
        if ($data instanceof ErrorReply) {
            echo '# error reply: ' . $data->getMessage() . PHP_EOL;
        } else {
            echo '# reply: ' . json_encode($data->getValueNative()) . PHP_EOL;
        }
    });

    $loop->addReadStream(STDIN, function () use ($client, $loop) {
        $line = fgets(STDIN);
        if ($line === false || $line === '') {
            echo '# CTRL-D -> Ending connection...' . PHP_EOL;
            $client->end();
        } else {
            $line = rtrim($line);

            if ($line === '') {

            } else {
                $params = explode(' ', $line);
                $method = array_shift($params);
                call_user_func_array(array($client, $method), $params);
            }
        }
    });

    $client->on('close', function() use ($loop) {
        echo '## DISCONNECTED' . PHP_EOL;

        $loop->removeReadStream(STDIN);
    });
}, function (Exception $error) {
    echo 'CONNECTION ERROR: ' . $error->getMessage() . PHP_EOL;
    exit(1);
});

Only show:

➜  Test git:(master) ✗ php test2.php
# connecting to redis...

Race condition when submitting multiple commands

I frequently see promises being resolved with results that incorrect format, ie:

  • HGETALL resolves with a string.
  • HGETALL resolves with an array but with the wrong fields
  • GET resolves with an array.
  • etc..

I cannot confirm but I believe the problem is a race that occurs when a command is being submitted and a response is already queued up on the socket or is queued up before the write resolves but before it finishes. I'm still not clear on this, but I have seen the problem enough times to know it is real.

I will submit an actual test as soon as I can, hopefully with a PR as well.

how to run in MVC

HI @clue This project is very good
I want to integrate him into MVC,but I don't know how to do it

I've been trying for a long time,

I hope the great God for advice

Thanks

Requests within Multi-Exec should only be resolved by EXEC reply

Currently, each request is fulfilled as soon as a reply is received. For requests within a multi-block, each request is thus fulfilled with a value of "QUEUED".

Would be nice if we would instead switch to a dedicated state where each "QUEUED" reply only issues a "progress". Each request should be fulfilled once the EXEC-reply has been received which includes an array of all results.

Obviously, we have to cope with invalid requests (nested MULTI), invalid arguments, etc.

Can't Pub/Sub On Same Client

It appears that pub sub is not really async. After trying to figure out why I wasn't receiving commands on another client, I finally tried commenting out $client->subscribe($channel); and all of a sudden the publish commands were going through.

With a client subscribe the following code never logged the publish complete message:

$this->redis->publish($this->channel, json_encode($msg))->then(function($return) {
    $this->debug('Publish received ' . $return);
});

Can't connect to local DNS name

I have a local DNS alias in my /etc/hosts just named redis wich points to my Redis server when I try to create the client with the Factory::createClient using this DNS the React\Dns\Resolver\Resolver search for it in this server 8.8.8.8 (Google's DNS Server) and can't resolve because it's local.

Assosiative array serializer

Hi

I want to cache result of mysql queries in redis , As I use MYSQLI_ASSOC my data is in associative array format , So converting associative array to pass it to Clue\Redis is not optimize

Can you please implement Assosiative array serializer so we can do like this

 $client->HSET('myhash',[
    'field1' => 'hello',
    'field2' => 'world',
]);

No I must convert it to ['field1','hello','field2','world'] and then

 $client->HSET('myhash',... ['field1','hello','field2','world']);

Composer fails to install redis-react

With the following composer configuration:

{
    "require": {
        "react/react": "*",
        "react/stomp": "*",
        "cboden/Ratchet": "*",
        "clue/redis-react": "dev-master"
    }
}

I get this error:

$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for clue/redis-react dev-master -> satisfiable by clue/redis-react[dev-master].
    - clue/redis-react dev-master requires clue/redis-protocol dev-master -> no matching package found.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stability setting
   see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> for more details.

Client interface methods

I've been working with react php for a few weeks now and since today I'm trying out this package. So far it seems to work fine but I'm missing a few methods inside the Client interface, such as: subscribe, publish, get and set. I don't know if this was intentional but I would like to see it sometime in the future.

Docker support

When I use Clue\React\Redis\Factory

$factory = new Factory($loop);
$factory->createClient('redis_docker_aliase')
->then(....
...

I see error

exception 'React\SocketClient\ConnectionException' with message 'Connection refused' in /code/vendor/react/socket-client/React/SocketClient/Connector.php:76
Stack trace:
#0 [internal function]: React\SocketClient\Connector->checkConnectedSocket(Resource id #185)
#1 /code/vendor/react/promise/src/React/Promise/FulfilledPromise.php(20): call_user_func(Array, Resource id #185)
#2 /code/vendor/react/promise/src/React/Promise/Deferred.php(39): React\Promise\FulfilledPromise->then(Array, NULL)
#3 [internal function]: React\Promise\Deferred->React\Promise\{closure}(Object(React\Promise\FulfilledPromise))
#4 /code/vendor/react/promise/src/React/Promise/Deferred.php(102): call_user_func(Object(Closure), Object(React\Promise\FulfilledPromise))
#5 /code/vendor/react/promise/src/React/Promise/Deferred.php(60): React\Promise\Deferred->processQueue(Array, Object(React\Promise\FulfilledPromise))
#6 /code/vendor/react/socket-client/React/SocketClient/Connector.php(65): React\Promise\Deferred->resolve(Resource id #185)
#7 [internal function]: React\SocketClient\Connector->React\SocketClient\{closure}(Resource id #185, Object(React\EventLoop\StreamSelectLoop))
#8 /code/vendor/react/event-loop/React/EventLoop/StreamSelectLoop.php(160): call_user_func(Object(Closure), Resource id #185, Object(React\EventLoop\StreamSelectLoop))
#9 /code/vendor/react/event-loop/React/EventLoop/StreamSelectLoop.php(169): React\EventLoop\StreamSelectLoop->runStreamSelect(true)
#10 /code/vendor/react/event-loop/React/EventLoop/StreamSelectLoop.php(182): React\EventLoop\StreamSelectLoop->loop()

Incorrect usage Promise interface with new React

On trying use: subscribe functionality or (eg. examples/monitor.php)

PHP Fatal error: Call to undefined method React\Promise\Deferred::then() in /var/www/projects/DomainScrapper/vendor/clue/redis-react/src/StreamingClient.php on line 105

Fix documentation for on pmessage.

The docs has this for on pmessage..

$client->on('pmessage', function ($pattern, $payload) {
}

It should be this ...

$client->on('pmessage', function ($pattern, $channel, $payload) {
}

Where $channel is the channel it matches.

NULL

I use the following code

$client->HMSET('test','a'=>'z','b'=>null);

But when I use the following code

$client->HGETALL('test');

field b is empty string not null , How can I get it as null? without serialize , json and ...

can't connect to a digital ocean managed Redis cluster on version 5.0.6

Hi,
I can't connect to a digital ocean managed Redis cluster on version 5.0.6
With the code bellow I get the error "Unable to subscribe: Connection to Redis server failed because AUTH command failed"
But using only predis I can cannot with no issues. Can you help me? I think the issue is with the fact that it uses tls

       $connector = new \React\Socket\Connector($loop, array(
            'tls' => array(
                'verify_peer' => false,
                'verify_peer_name' => false
            )
        ));

        $factory = new Factory($loop, $connector);

        $client = $factory->createLazyClient(
            'redis://'.$settings['host'].':'.$settings['port'].'?password='.$settings['password'].'&db='.$settings['database']
        );

Error: Unable to subscribe: Connection to Redis server failed because AUTH command failed

Failure to connect is not indicated with rejected promise

Using essentially this code:

$_factory = new Factory($loop);
$_factory
    ->createClient("redis://$_host:$_port")
    ->then(function(Client $client) use($_host, $_port) {
        $logger->info("Redis connected to $_host:$_port");
    },
    function(\Exception $ex) {
        $logger->error("Failed to connect to Redis:\n$e");
    });

I have Redis turned off, so connections should fail. However, the code is always printing "Redis connected to host:port" instead of "Failed to connect to Redis:...".

The only way I can seem to detect that it failed to connect is to subscribe to the "close" event, which does fire when the connection attempt fails. However, this cannot be so easily included in a promise chain. In fact, since there is no opposite event (we only have close for failure, but not open for success), it's actually impossible to detect if the connection succeeded. The only way I can think of is to attempt a command like PING and chain promises from there. But surely there must be a better way. Am I missing something? Is this something that can be fixed?

Timeout

How can I set a timeout for redis command , that means if I don't get response within a time then reject the promise

Redis Streams example?

Is there an example of using this library with the Streams data structure introduced in Redis v5?

use `redis-react` to subscribe message,how to reconnect

my code is below

$factory->createClient("{$redisHost}:{$redisPort}")->then(function (Client $client) {
    $client->subscribe('device_change')->then(function () {
        echo 'Now subscribed to channel ' . PHP_EOL;
    });

    $client->on('message', function ($channel, $message) {
        echoln("get message"));
    });

    $client->on('close', function () {
        echoln('close');

        //set a Timer to reconnect the connect
        $timer_id = Timer::add(5, function () use (&$timer_id) {
            // todo ,here how to reconnect
            // 

        });

    });
    $client->on('error', function (Exception $e) {
        echoln('error' . $e->getMessage());
    });
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.