Hello,
I use laravel 5.0.33, installed phpredis and have the following configuration :
In app.php
'PhpRedis' => 'Illuminate\Support\Facades\Redis',
In queue.php
'redis' => [
'driver' => 'redis',
'queue' => 'default',
'connection' => 'default',
'expire' => 60,
],
In database.php
'redis' => [
'cluster' => false,
'default' => [
'host' => '192.168.33.100',
'port' => 6379,
'prefix' => '',
'database' => 0,
'timeout' => 0,
'serializer' => 'igbinary',
'persistent' => false
],
Jobs are pushed successfully in queues but when I try to start a queue, I get the following error :
$ php artisan queue:listen --queue=images --tries=3
PHP Fatal error: Call to undefined method Redis::transaction() in /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php on line 179
[2015-08-31 20:04:49] local.ERROR: exception 'Symfony\Component\Debug\Exception\FatalErrorException' with message 'Call to undefined method Redis::transaction()' in /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php:179 Stack trace:
#0 {main}
[Symfony\Component\Debug\Exception\FatalErrorException]
Call to undefined method Redis::transaction()
Let me know if I can provide more valuable information.
This is probably the same reason as in #1066.
Comment with solution.
@dmgawel thank you for trying to help.
I already stumbled upon those posts and as you can see I already changed my alias.
As per the second method, I tried adding the following to RedisQueue.php file :
use Illuminate\Support\Facades\Redis;
but I still get the same error. The redis cache driver works so I tried to set :
use Illuminate\Redis\Database as Redis;
instead of
use Illuminate\Redis\Database;
in the RedisQueue.php file (same as in the RedisStore.php) but it fails with the error :
[2015-09-01 14:07:24] local.ERROR: exception 'ErrorException' with message 'Argument 1 passed to Illuminate\Queue\RedisQueue::__construct() must be an
instance of Illuminate\Queue\Database, instance of App\MyProviders\Database given, called in /var/www/app/vendor/laravel/framework/src/Illuminate/Que
ue/Connectors/RedisConnector.php on line 45 and defined' in /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php:46
Stack trace:
#0 /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php(46): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(4096,
'Argument 1 pass...', '/var/www/app/ve...', 46, Array)
#1 /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/Connectors/RedisConnector.php(45): Illuminate\Queue\RedisQueue->__construct(Object(App\M
yProviders\Database), 'default', 'default')
#2 /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/QueueManager.php(114): Illuminate\Queue\Connectors\RedisConnector->connect(Array)
#3 /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/QueueManager.php(94): Illuminate\Queue\QueueManager->resolve('redis')
#4 /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(148): Illuminate\Queue\QueueManager->connection(NULL)
#5 /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(110): Illuminate\Queue\Worker->pop(NULL, 'emails', '0', '3', '3'
)
#6 /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(70): Illuminate\Queue\Console\WorkCommand->runWorker(NULL, 'emai
ls', '0', '128', false)
#7 [internal function]: Illuminate\Queue\Console\WorkCommand->fire()
#8 /var/www/app/vendor/laravel/framework/src/Illuminate/Container/Container.php(526): call_user_func_array(Array, Array)
#9 /var/www/app/vendor/laravel/framework/src/Illuminate/Console/Command.php(115): Illuminate\Container\Container->call(Array)
#10 /var/www/app/vendor/symfony/console/Symfony/Component/Console/Command/Command.php(257): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#11 /var/www/app/vendor/laravel/framework/src/Illuminate/Console/Command.php(101): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#12 /var/www/app/vendor/symfony/console/Symfony/Component/Console/Application.php(874): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#13 /var/www/app/vendor/symfony/console/Symfony/Component/Console/Application.php(195): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Queue\Console\WorkCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 /var/www/app/vendor/symfony/console/Symfony/Component/Console/Application.php(126): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(94): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 /var/www/app/artisan(36): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#17 {main}
[ErrorException]
Argument 1 passed to Illuminate\Queue\RedisQueue::__construct() must be an instance of Illuminate\Queue\Database, instance of App\MyProviders\Databa
se given, called in /var/www/app/vendor/laravel/framework/src/Illuminate/Queue/Connectors/RedisConnector.php on line 45 and defined
I use phpredis service provider found here : https://github.com/vetruvet/laravel-phpredis
The following code works :
$redis = PhpRedis::connection();
$redis->set('name', 'Dave');
$name = $redis->get('name');
Cache::forever('name', 'Dave');
$name = Cache::get('name');
Queue::push('MyService@test', array(
'test' => 'content'
), 'myqueue');
PhpRedisServiceProvider.php added in app.php "App\MyProviders\PhpRedisServiceProvide" :
<?php namespace App\MyProviders;
use Illuminate\Support\ServiceProvider;
class PhpRedisServiceProvider extends ServiceProvider {
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->bindShared('redis', function($app)
{
return new Database($app['config']['database.redis']);
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('redis');
}
}
Database.php
<?php namespace App\MyProviders;
use \Redis;
use \RedisArray;
class Database extends \Illuminate\Redis\Database {
/**
* Create a new aggregate client supporting sharding.
*
* @param array $servers
* @return array
*/
protected function createAggregateClient(array $servers) {
$options = array(
'lazy_connect' => true,
'pconnect' => false,
'timeout' => 0,
);
$cluster = array();
foreach ($servers as $key => $server) {
if ($key === 'cluster') continue;
$host = empty($server['host']) ? '127.0.0.1' : $server['host'];
$port = empty($server['port']) ? '6379' : $server['port'];
$serializer = Redis::SERIALIZER_NONE;
if (!empty($server['serializer'])) {
if ($server['serializer'] === 'none') {
$serializer = Redis::SERIALIZER_PHP;
} else if ($server['serializer'] === 'igbinary') {
if (defined('Redis::SERIALIZER_IGBINARY')) {
$serializer = Redis::SERIALIZER_IGBINARY;
} else {
$serializer = Redis::SERIALIZER_PHP;
}
}
}
$cluster[$host.':'.$port] = array(
'prefix' => empty($server['prefix']) ? '' : $server['prefix'],
'database' => empty($server['database']) ? 0 : $server['database'],
'serializer' => $serializer,
);
if (isset($server['persistent'])) {
$options['pconnect'] = $options['pconnect'] && $server['persistent'];
} else {
$options['pconnect'] = false;
}
if (!empty($server['timeout'])) {
$options['timeout'] = max($options['timeout'], $server['timeout']);
}
}
$ra = new \RedisArray(array_keys($cluster), $options);
foreach ($cluster as $host => $options) {
$redis = $ra->_instance($host);
$redis->setOption(Redis::OPT_PREFIX, $options['prefix']);
$redis->setOption(Redis::OPT_SERIALIZER, $options['serializer']);
$redis->select($options['database']);
}
return array('default' => $ra);
}
/**
* Create an array of single connection clients.
*
* @param array $servers
* @return array
*/
protected function createSingleClients(array $servers) {
$clients = array();
foreach ($servers as $key => $server) {
if ($key === 'cluster') continue;
$redis = new Redis();
$host = empty($server['host']) ? '127.0.0.1' : $server['host'];
$port = empty($server['port']) ? '6379' : $server['port'];
$timeout = empty($server['timeout']) ? 0 : $server['timeout'];
if (isset($server['persistent']) && $server['persistent'] != false) {
$connected = $redis->pconnect($host, $port, $timeout);
} else {
$connected = $redis->connect($host, $port, $timeout);
}
if (!empty($server['prefix'])) {
$redis->setOption(Redis::OPT_PREFIX, $server['prefix']);
}
if (!empty($server['database'])) {
$redis->select($server['database']);
}
if (!empty($server['serializer'])) {
$serializer = Redis::SERIALIZER_NONE;
if ($server['serializer'] === 'php') {
$serializer = Redis::SERIALIZER_PHP;
} else if ($server['serializer'] === 'igbinary') {
if (defined('Redis::SERIALIZER_IGBINARY')) {
$serializer = Redis::SERIALIZER_IGBINARY;
} else {
$serializer = Redis::SERIALIZER_PHP;
}
}
$redis->setOption(Redis::OPT_SERIALIZER, $serializer);
}
$clients[$key] = $redis;
}
return $clients;
}
}
@GrahamCampbell could you reopen please ?
No, it's not a bug.
Any idea on why this is failing ?
Because it's a bug as you say @trompx , they just don't wanna realize it. You have to change the alias to get around it, which in my book defines a bug... many have criticized it.
Any update?
This error is caused by different implement of transaction (used in migrating expired jobs in redisqueue) in phpredis and predis, it can not be simply solved by adding a alias.
I hope laravel redis queue can support both phpredis and predis? Or?
@trompx or @phoenixgao have either of you figured out a fix for this issue? I thought I was good to go after submitting a PR to the laravel-phpredis library to support AUTH. Now I find that I can't actually process the queue because the expired jobs processing is essentially hard-coded to PRedis, and it's transaction() method, that the PECL PhpRedis doesn't implement. So what to do? :-/
I don't know why this is closed. It's a bug. Laravel/Lumen uses the Predis implementation instead of Redis (PECL).
I thought Predis was used in the case you couldn't install the proper extension.
@GrahamCampbell is this still valid?
That library will use the extension if installed under the hood.
https://github.com/laravel/framework/issues/11692#issuecomment-168973452
Most helpful comment
Any update?
This error is caused by different implement of transaction (used in migrating expired jobs in redisqueue) in phpredis and predis, it can not be simply solved by adding a alias.
I hope laravel redis queue can support both phpredis and predis? Or?