Redis Cache


(Gustavo) #1

Use Redis as your cache system

Redis is a great cache system, it store the cache in ram and send it to the hard drive once in a while, so you dont lose when the pc shut down

Simply add the 2 download files to your protected/components folder

##Requirements

PHP 5.2.x

##Usage

define in the application’s configuration array




 'components'=>array(

 		'cache'=>array(

 			'class'=>'CRedisCache',

//if you dont use servers options it will use the default one "host=>'127.0.0.1',port=>6379"

 			'servers'=>array(

 				array(

 					'host'=>'server1',

 					'port'=>6379,

 				),

 				array(

 					'host'=>'server2',

 					'port'=>6379,

 				),

 			),

 		),

 	),




then you can use any redis function by calling




Yii::app()->cache->{function}(args);



##Resources

It uses Predis as redis php client

  • [Redis page] (redis)

  • [Predis page] (Predis)


(Gustavo) #2

added as an extension here


(Luoyy) #3

CException

Property "CRedisCache.servers" is read only?


(Gustavo) #4

when ?

what did you do ?

could you show me the part of the code that throws the exception ?

Thanks


(Luoyy) #5

nginx 0.8.54

php 5.3.4

yii 1.1.6.r2877

php redis 2.1.0

I am download rediscache from /extension/rediscache/


and copy to protected/extensions/


                protected/extensions/redis/CRedisCache.php

                protected/extensions/redis/Predis.php







conf/main.php

'cache'=>array( 

	'class'=>'ext.redis.CRedisCache', 

	'servers'=>array( 

		array( 

			'host'=>'192.168.100.206', //redis master

			'port'=>6379, 

		),

		/*

		array( 

			'host'=>'192.168.100.207',

			'port'=>6379, 

		),

		array( 

			'host'=>'192.168.100.208',

			'port'=>6379, 

		), 

		array( 

			'host'=>'192.168.100.209',

			'port'=>6379, 

		),*/

	), 

), 



create a module "user"

protected/modules/user/models/User.php




class User extends CBaseDao {

	public function testRedisCache() {

		$sql = "SELECT username FROM account";

		$data = $this->slave()->createCommand($sql);

		//return Yii::app()->cache->set(md5($sql), $data, 3600);

		return Yii::app()->cache->set('test', 12345, 3600);

	}

}



then I get the error message:

Property "CRedisCache.servers" is read only

/home/framework/YiiBase.php(214)




213 foreach ($config as $key=>$value)

214	$object->$key=$value;

215

216 return $object;




(Luoyy) #6



59 public function getServers()

60 {

61     if($this->servers!==null){

62          $this->_servers=$this->servers;

63          $this->servers=null;

64     }

65     return $this->_servers;

66 }



61, Undefined property: CRedisCache::$servers

add


protected $servers=array();

CRedisCache.php


require_one Yii::getPathOfAlias($this->predisPath);

require_once(/home/luoyinyou/webgame/app/protected/extensions/redis/Predis) filed to open stream: No such file or directory


require_one Yii::getPathOfAlias($this->predisPath).'.php';

oh…

Property CRedisCache.useMasterDb is not defined…

then I go to eat…


(Gustavo) #7

Fixed the bug, new file can be found in the extension page


(Ice Deng) #8

solve :Property "CRedisCache.servers" is read only

update getRedis() method:

old:


Yii::import("application.extensions.redis.Predis.php"); 

new:


Yii::import("application.extensions.redis.Predis", true);

append method:


public function setServers($config)

{

	$this->_servers= $config;

}


(Gustavo) #9

Thanks Ice

I have solved it another way

Did you try the new download in the extension page ?

Its working properly now.

Anyway, thanks for sharing your fix


(Ice Deng) #10

php 5.3.5

yii 1.1.6.r2877

The new version is still have problems

error:

CException

属性 "CRedisCache.servers" 是只读的.


(Gustavo) #11

Huh …

odd … .

work normally here at home and at work …

gonna check it out and give you a feedback soon


(Ice Deng) #12

http://www.yiiframework.com/ext/files/?id=348

redis.zip (18.7 KB)

version 0.3

Released on Feb 25, 2011; downloaded 0 times.

I use the above version,may not be the latest.


(Gustavo) #13

Thanks

I just deleted the old one to not cause confusion

the version 0.3 is the right one …

This one is the one that is working to me


(Gustavo) #14

That is because you must set cache inside ‘components’ index in the config


(Roman Kutsy) #15

How I can set Redis database when I need store/get data?

Can I flush only one Redis database (by setting dbindex)?

I mean smth like this:




Yii::app()->cache->setValue($key, $value, $expire, $dbindex);

Yii::app()->cache->getValue($key, $dbindex);

Yii::app()->cache->flush($dbindex);




(Gustavo) #16

Hi Kutsy

You should have no problem by using any redis default function ( predis client implemented it all ) since the extension uses __call() magic method




$cache=Yii::app()->getCache();

//selects a database

$cache->select($db);

//flushs the database

$cache->flushdb();

//or set/get to/from this database

$cache->set('index','value',60);

$cache->get('index');



Anyway, I’ll think about to implement the methods you suggested

Thanks


(Roman Kutsy) #17

OK, thanks.


(Pringlized) #18

What do you do when the redis connection is down? I’ve been pulling my hair out on this. Everything works great when redis is up and running. So I wanted to test and build a solid fall back to the DB when redis was down. The problem became apparent when I realized that the init() of CRedisCache does not create a connection or ping for the sign of a connection. But once I execute a command against the cache, if the connection is down Predis will throw the exception Predis_CommunicationException.

I never thought this would be an issue. Anytime I called a Yii::app()->cache-> command I wrapped it in try/catch blocks and caught Predis_CommunicationException. My problem is that even if I catch the error, it still exists in the Yii exception head space and I kills the stack at a later point.

When I put the following in my config/main.php, it eliminates the display of any error data which was an earlier problem. Unfortunately, the exception is still sitting in the errorHandler on CApplication(i think that’s the obj location). And because of that, CApplication->handleError is still called down the stack and it exits the app instead of skipping over the exception.




'onException' => function($event)

{

    if ($event->exception instanceof Predis_CommunicationException)

    {

        $event->handled = true;

    }

},



When I attempt to get a key from redis, I call this. Be reminded, when redis is up this works like a charm. It’s only the persistence of the catch (when redis is down) in Yii’s errorHandler that is the problem site wide.




try

{

    $debtorCache = Yii::app()->cache->get($key);

    if(empty($debtorCache))

    {

        // this works great....

        // get data from db..

	// set cache data

	// return data

    }

    else

    {

        // this works great....

        list($debtorData, $caseData, $paymentData, $activityData) = $debtorCache;

    }

}

catch(Predis_CommunicationException $e)

{

    // displays just fine before CApplication handleError exits....

    echo "{$e->getFile()}:{$e->getLine()}: Redis is down..<br>";

}



I kept getting a standard Yii uncaught exception that gave the error name and message which killed the app.

FYI: I use PHPStorm with xdebug. I ran through the stack on this one line by line, and stepped into every call. I couldn’t figure out why the Predis exception was still being called after I caught it. Looks like even setting an event->exception to “handled” still gets a exit(1). Curious why.

I’m starting to think this has something to do with how Yii manages “uncaught” exceptions in the handleError() in CApplication. Not sure what to make of this since I have caught the error everytime I call Yii::app()->cache, and by using CApplication->onException in config/main.php, set $event->handled.

Any help would be greatly appreciated.


(Alsadi) #19

updated to use the latest stable Predis 7.2 and it’s attached

2926

redis.zip

put redis so that its Autoloader.php is redis/Autoloader.php where redis directory is next to CRedisCache.php

here is the diff




@@ -50,9 +60,12 @@

                if($this->_cache!==null)

                        return $this->_cache;

                else{

-            require_once Yii::getPathOfAlias($this->predisPath).".php";

+            // to use the old single file appreach comment out the next two lines and uncomment the 3rd

+            require_once Yii::getPathOfAlias($this->predisPath).'/Autoloader.php';

+            Predis\Autoloader::register();

+            //require_once Yii::getPathOfAlias($this->predisPath).'.php'; // old single file approach,no autoloading

             Yii::log('Opening Redis connection',CLogger::LEVEL_TRACE);

-                       return $this->_cache=new Predis_Client($this->servers);

+                       return $this->_cache=new Predis\Client($this->servers);

         }

        }




(Danvan8511) #20

apache 2.2

yii 1.1.12

redis server 2.4.6

I’ve got NotSupportedException while trying to use ‘watch’ command within this extension.

By my debugging, the watch command cannot be hashed. Is there anyone can tell me how to apply this command? Thanks a lot.

Here is the debug info: