i try to add a key-value-pair in my redis-cluster and set expire for the new key in one pipeline. Every time i get an error that the key is moved, but i think that Predis should follow the MOVED-statement like without pipelining.
Isn't it possible to make an expire-call in the pipe? I'm using Predis 1.0.2-dev
with redis_version: 3.0.2
This works:
$parameters = ['tcp://10.9.200.51:47801', 'tcp://10.9.200.52:47801', 'tcp://10.9.200.53:47801', 'tcp://10.9.200.54:47801'];
$options = ['cluster' => 'redis'];
$redis = new Predis\Client($parameters, $options);
for($i = 0; $i < 10; $i++)
{
$rand = mt_rand(1111111,9999999);
$k = 'test_'.$rand;
try{
$redis->set($k, 1);
$redis->expire($k, 10);
}
catch(Exception $ex)
{
print_r($ex);
}
}
?>
This does not work:
$parameters = ['tcp://10.9.200.51:47801', 'tcp://10.9.200.52:47801', 'tcp://10.9.200.53:47801', 'tcp://10.9.200.54:47801'];
$options = ['cluster' => 'redis'];
$redis = new Predis\Client($parameters, $options);
$pipe = $redis->pipeline();
for($i = 0; $i < 10; $i++)
{
$rand = mt_rand(1111111,9999999);
$k = 'test_'.$rand;
try{
$pipe->set($k, 1);
$pipe->expire($k, 10);
}
catch(Exception $ex)
{
print_r($ex);
}
}
$pipe->execute();
?>
I get this error:
PHP Fatal error: Uncaught exception 'Predis\Response\ServerException' with message 'MOVED 7276 10.9.200.61:47902' in /var/www/predis_test/Predis/Pipeline/Pipeline.php:105
Stack trace:
#0 /var/www/predis_test/Predis/Pipeline/Pipeline.php(149): Predis\Pipeline\Pipeline->exception(Object(Predis\Connection\Aggregate\RedisCluster), Object(Predis\Response\Error))
#1 /var/www/predis_test/Predis/Pipeline/Pipeline.php(168): Predis\Pipeline\Pipeline->executePipeline(Object(Predis\Connection\Aggregate\RedisCluster), Object(SplQueue))
#2 /var/www/predis_test/Predis/Pipeline/Pipeline.php(217): Predis\Pipeline\Pipeline->flushPipeline()
#3 /var/www/predis_test/lasttest.php(31): Predis\Pipeline\Pipeline->execute()
#4 {main}
thrown in /var/www/predis_test/Predis/Pipeline/Pipeline.php on line 105
EDIT: Seems that pipelining doens't work on redis-cluster. I get the same error when I remove the expire call and have only the set call in a pipe.
Predis pipeline requires the keys in the same SLOT in cluster(for cluster support auto sharding), which makes it hard for client to handle received moved message from redis cluster server.
More details please refer to the following issue and discussion:
Issue: Pipelining with redis-cluster throws exception #267
Discussion: Redis Cluster with Pipeline
The Conclusion is: do not use pipeline under redis cluster.
Related
Testing Redis pub/sub in my Laravel app. Executing this artisan command
public function callback(){
print_r(func_get_args());
}
public function handle(): int
{
$client = Redis::connection()->client();
if($client->isConnected()){
$this->line('Connected'); // Prints "Connected"
}
$client->subscribe(['exchanges'], [$this, 'callback']);
$client->publish('exchanges', json_encode($this->getExchanges()));
return 0;
}
gives this error:
read error on connection to 127.0.0.1:6379
at app/Console/Commands/Client/Start.php:49
45▕ if($client->isConnected()){
46▕ $this->line('Connected');
47▕ }
48▕
➜ 49▕ $client->subscribe(['exchanges'], [$this, 'callback']);
50▕ $client->publish('exchanges', json_encode($this->getExchanges()));
51▕
52▕ return 0;
53▕
1 app/Console/Commands/Client/Start.php:49
Redis::subscribe()
Whats wrong with subscribe() method?
ini_set('default_socket_timeout', -1) Works for me.
I'm using Google Cloud SQL 2nd generations instances and persistent connections using PHP PDO driver but, from time to time, and just in some App Engine instances, the pooled connections get corrupted and the connections begin to fail, sending an ugly message to the user.
I tried to solve this trying to make new connnections, even disabling persistency, but it didn't work:
for ($attempt = 1; !$this->link; $attempt++) {
try {
if ($attempt > $persistent / 2) {
unset($options[PDO::ATTR_PERSISTENT]);
}
$this->link = new PDO($dsn_string, $user, $pass, $options);
} catch (PDOException $err) {
if ($attempt <= $persistent) {
usleep($attempt * 100000);
} else {
throw new DB_Exception("Error connecting database (after $attempt attempts):\n" . $err->getMessage(), $err->getCode(), null, $err);
}
}
}
I am using this code below to deal with the REST API query for Adobe Analytics. I always get the message "something went wrong" which means that the first IF is not active.
include_once('/path/SimpleRestClient.php');
$username = 'XXXXX';
$secret = 'XXXXX';
$nonce = md5(uniqid(php_uname('n'), true));
$nonce_ts = date('c');
$digest = base64_encode(sha1($nonce.$nonce_ts.$secret));
$server = "https://api.omniture.com";
$path = "/admin/1.4/rest/";
$rc=new SimpleRestClient();
$rc->setOption(CURLOPT_HTTPHEADER, array("X-WSSE: UsernameToken Username=\"$username\", PasswordDigest=\"$digest\", Nonce=\"$nonce\", Created=\"$nonce_ts\""));
$query="?method=Company.GetTokenUsage";
$rc->getWebRequest($server.$path.$query);
if ($rc->getStatusCode()==200)
{
$response=$rc->getWebResponse();
var_dump($response);
}
else
{
echo "something went wrong\n";
var_dump($rc->getInfo());
}
The $rc->getStatusCode(); does not exit. I get '404' when I use this line :
print_r ($rc->getStatusCode());
After googling, I found https://marketing.adobe.com/developer/blog/how-to-start-with-the-omniture-rest-api-in-php. It uses API version of 1.3 instead of 1.4. By updating the
$path = "/admin/1.4/rest/";
to
$path = "/admin/1.3/rest/";
I was able to stop getting 404 errors in the browser.
I am trying to get gmail attachments using batch requests on the gmail API. It sometimes works, but if I rerun it, I'll get errors a large percentage of the time. I'd like to catch the errors and take appropriate action - like exponential backoff, which will (hopefully) fix the problem. But it's not working.
Here is the code:
for ($n = 0; $n < 5; ++$n) {
try {
$results = $batch->execute();
break;
} catch (Google_Service_Exception $e) {
if ($e->getError() != '') { //placeholder
// Apply exponential backoff.
usleep((1 << $n) * 1000 + rand(0, 1000));
}
}
}
for ($i=1; $i < $stop+1; $i++) {
$message = $results['response-'.$i];
if ($message2->getPayload()) { ...
The error logs show that sometimes I'm immediately trying to call Google_Service_Exception::getPayload. It's as if each response in the batch was itself a Google_Service_Exception object, or at least the first one.
How do I catch errors in a batch?
my sort command is
"SORT hot_ids by no_keys GET # GET msg:->msg GET msg:->count GET msg:*->comments"
it works fine in redis-cli, but it doesn't return data in RedisClient. the result is a byte[][], length of result is correct, but every element of array is null.
the response of redis is
...
$-1
$-1
...
c# code is
data = redis.Sort("hot_ids ", new SortOptions()
{
GetPattern = "# GET msg:*->msg GET msg:*->count GET msg:*->comments",
Skip = skip,
Take = take,
SortPattern = "not-key"
});
Redis Sort is used in IRedisClient.GetSortedItemsFromList, e.g. from RedisClientListTests.cs:
[Test]
public void Can_AddRangeToList_and_GetSortedItems()
{
Redis.PrependRangeToList(ListId, storeMembers);
var members = Redis.GetSortedItemsFromList(ListId,
new SortOptions { SortAlpha = true, SortDesc = true, Skip = 1, Take = 2 });
AssertAreEqual(members,
storeMembers.OrderByDescending(s => s).Skip(1).Take(2).ToList());
}
You can use the MONITOR command in redis-cli to help diagnose and see what requests the ServiceStack Redis client is sending to redis-server.