CI3 – redis code example

check the previous ci3 and redis setup

cat application/controllers/Tredis.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');
require_once APPPATH . 'libraries/codeigniter-predis/src/Redis.php';
require_once APPPATH . 'libraries/codeigniter-predis/src/RedisServer.php';
require_once APPPATH . 'libraries/codeigniter-predis/src/RedisServerCollection.php';


class Tredis extends CI_Controller
{
	function queue()
	{

		$this->redis = new \CI_Predis\Redis(['serverName' => 'redis']);

		$data = [];

		foreach ($_POST as $var => $_) $data[$var] = $this->input->post($var);

		echo $this->redis->rpush("costumer_register", json_encode($data));

		echo "Customer details accepted successfully.\n";
	}

	function worker()
	{
		$this->redis = new \CI_Predis\Redis(['serverName' => 'redis']);

		$data = $this->redis->lpop('costumer_register');

		$data  = json_decode($data, true);

		if (!empty($data)) {

			$this->load->model('foo/foo_m');

			$this->foo_m->__insert('testtest', $data);

			echo $data['first_name'] . " " . $data['last_name'] . "'s details saved to database.";
		} else {
			echo "No data in customers_register \n";
		}
	}
}

we need to create testtest table

CREATE TABLE `testtest` (
  `id` int(11) NOT NULL,
  `first_name` varchar(128) DEFAULT NULL,
  `last_name` varchar(128) DEFAULT NULL,
  `email_address` varchar(128) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

now let test with curl fill data

$ curl --insecure --data "first_name=JOHN&last_name=DOE&email_address=john_doe@example.com" https://localhost/tredis/queue
$ curl --insecure --data "first_name=MARY&last_name=SMITH&email_address=mary_smith@example.com" https://localhost/tredis/queue
$ curl --insecure --data "first_name=JANE&last_name=COTTON&email_address=mary_smith@example.com" https://localhost/tredis/queue

and test worker

$ curl --insecure https://localhost/tredis/worker

source https://www.vultr.com/docs/implement-redis-queue-and-worker-with-php-on-ubuntu-20-04/

redis docker codeigniter 3

kenapa saya membutuhkan cache ? apakah kecapatan ? IO ? atau biar keren kayak yg lain ? jawabannya karena saya tidak suka system yg mubajir.

contoh system mubajir adalah, kita butuh 1 value dari rows database, untuk 1000 jobs, lalu kita query 1000 kali untuk mendapat 1 value itu. klo itu database bisa ngomong pasti dia protes "ini udah 1000 kali lo tanya hal yang sama, 1 kali lagi lo tanya, gw ngambek".

contoh diatas bisa diatasi menyimpan value itu ke sebuah variable, sehingga hanya 1 kali query ke db (IO) dan 1000 kali akses value itu ke RAM. karena variable disimpan ke dalam RAM, dan kecepatan pengaksesan value ke ram lebih cepat dari pada ke DB (IO) atau perangkat keras penyimpanan (HARDISK).

tapi kan hardisk server saya sudah SSD, kan cepet juga tuh kalo akses. iya, tapi SSD punya keterbatasan bacatulis dan umur. so enggak bijak lah kita bergantung cuma ke SSD tapi kodingan tidak di maximalkan.

kelebihan cache adalah untuk memproses jobs. jobs ini akan di execute oleh script yg diperiodekan oleh cronjob.

jobs nya cukup banyak bisa sampai di atas 5K jobs. bayangkan jika 5K jobs ini melakukan query ke database, untuk sebuah rows yg sama, mencari value yg sama sebagai parameter, karena setiap jobs akan membuat ‘session’ sendiri sehingga jika kita buat cros variable jauh lebih rumit maintenance systemnya.sungguh tidak indah, dan riskan kesalahan.

yang paling baik dan pasti kita butuh kedepan dalam pengembangan fitur, adalah menggunakan REDIS sebagai cache.

pada project ini saya menggunakan docker (docker-compose) sebagai LAMP, sehingga menambah 1 server REDIS harus nya bukan masalah besar. dan script yg digunakan adalah codeigniter 3. kenapa CI3, karena project yg mau di implement cache ini base script nya CI3 dengan HMVC.

berikut step2 nya 0. to project folder

$ cd ~/workspace/ci3
  1. install redis pada docker-compose
$ cat docker-compose.yml

this is the content

version: "3"
services:
  php-apache:
   ...

  mariadb:
    ...

  phpmyadmin:
    ...

  redis:
    build:
      context: ./sys/redis
    networks:
      - gw_network

networks:
  gw_network:
    external: true

ini sys/redis folder punya 2 file Dockerfile and redis.conf

$ cat sys/redis/Dockerfile

FROM redis:3.2-alpine

COPY ./redis.conf /usr/local/etc/redis/redis.conf
CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]

EXPOSE 6379

and for redis.conf you can check this [https://github.com/DragonBe/docker-php-redis-example/blob/master/.docker/cache/conf/redis.conf]

now exec docker to pull and up redis server

docker-compose down
docker-compose build redis
docker-compose up -d
  1. add predis to codeigniter

my project path is ~/workspace/ci3 and ci3 code in ~/workspace/ci3/web install composer and install predis. to install composer we need php run on system, my laptop doest, so we need to go inside php-apache docker, but before that, we need to setup composer.json

$ cd ~/workspace/ci3/web
$ cat composer.json

{
    "require": {
        "predis/predis": "1.1.*@dev"
    },
    "autoload": {
        "psr-4": {"CI_Predis\\": "src/"}
    }
}

setup composer

$ cd ~/workspace/ci3
$ docker-compose up -d
$ docker-compose exec php-apache bash
root@a6d4050ee379:/var/www/html#
# echo "install composer"
# php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
# php -r "if (hash_file('sha384', 'composer-setup.php') === '55ce33d7678c5a611085589f1f3ddf8b3c52d662cd01d4ba75c0ee0459970c2200a51f492d557530c71c15d8dba01eae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
# php composer-setup.php
# php -r "unlink('composer-setup.php');"

install predis library with composer

# php composer.phar install
# exit

you can check in vendor folder

  1. add codeigniter-predi library

i am using code from this repo [https://github.com/Maykonn/codeigniter-predis] download only what we need

$ cd ~/workspace/ci3/web
$ mkdir -p application/libraries/codeigniter-predis &amp;&amp; cd application/libraries/codeigniter-predis/src
$ wget https://raw.githubusercontent.com/Maykonn/codeigniter-predis/master/src/Redis.php .
$ wget https://raw.githubusercontent.com/Maykonn/codeigniter-predis/master/src/RedisServer.php .
$ wget https://raw.githubusercontent.com/Maykonn/codeigniter-predis/master/src/RedisServerCollection.php .
$ cd application/config
$ wget https://raw.githubusercontent.com/Maykonn/codeigniter-predis/master/src/config/codeigniter-predis.php .
$ cd application/controllers/
$ wget https://raw.githubusercontent.com/Maykonn/codeigniter-predis/master/example/application/controllers/Welcome.php .

we need some change in config and controller. change config to

$ cat application/config/codeigniter-predis.php
 'localhost',
            'servers' => [
                'localhost' => [
                    'scheme' => 'tcp',
                    'host' => 'redis',
                    'port' => 6379,
                    'password' => null,
                    'database' => 0,
                ],
                // another instance
                'redis' => [
                    'scheme' => 'tcp',
                    'host' => 'redis',
                    'port' => 6379,
                    'password' => null,
                    'database' => 0,
                ],
            ],
        ];
        break;
    case 'homologation':
        break;
    case 'production':
        break;
    default:
        throw new Exception('The application environment is not set correctly.');
}

now change the Welcome.php

$ cat application/controllers/Welcome.php

<?php
defined("BASEPATH") or exit("No direct script access allowed");

class Welcome extends CI_Controller
{
    public function index()
    {
        require_once APPPATH . "libraries/codeigniter-predis/src/Redis.php";
        require_once APPPATH . "libraries/codeigniter-predis/src/RedisServer.php";
        require_once APPPATH . "libraries/codeigniter-predis/src/RedisServerCollection.php";

        echo "<pre>";

        echo 'See cms/config/codeigniter-predis.php file <br><br>';
        $this->load->config('codeigniter-predis.php');
        // Using the default_server configuration
        $this->redis = new \CI_Predis\Redis();
        echo 'PING server setted to default_server config param: ';
        echo $this->redis->ping() . '<br><br>';
        echo 'PING server setted to default_server config param, another way: ';
        echo $this->redis->getServerConnected()->ping() . '<br><br>';


        // Specifying hosts
        $this-&gt;redis = new \CI_Predis\Redis(['serverName' =&gt; 'redis']);

        // Ping the redis server
        echo 'PING redis server: ';
        echo $this->redis->ping() . '<br><br>';
        echo 'PING redis server again, another way: ';
        echo $this->redis->getServerConnected()->ping() . '<br><br>';


        $this->redis->getServersCollection()->getServer('another_instance_example')->ping() . '<br><br>';


        // Calling a command in a not connected server
        // echo 'PING a not connected server: <br>';
        // $this->redis->getServersCollection()->getServer('not_connected_server')->ping() . '<br>';
    }
}