26
loading...
This website collects cookies to deliver better user experience
sudo apt update
sudo apt install redis-server
sudo systemctl status redis
//to confirm the status of new redis server
//if not running ,you may need to start it by running
sudo service redis start
redis-server.exe
after which you can run redis-cli.exe to open redis terminal.ping
and if you receive back pong
, we are good to go.sudo apt-get install php-redis
sudo apt-get install php{x.x}-redis
//where x.x is your cli php version e.g 7.4
redis not found
error.predis
instead, start by installing the package predis/predis via composer using the command belowcomposer require predis/predis
configs/app.php
in the aliases
array, comment out the entry with the key Redis if already exists and replace with'LRedis' => Illuminate\Support\Facades\Redis::class,
configs/database.php
and in the connections array, replace the entry with key redis with the following code block.Note
intentionally leave out the prefix config out of the configs to avoid having to add prefix to channel's name or topic later on .'redis' => [
'client' => 'predis',
/*if you are using the php-redis extension,you can change 'predis' here to 'phpredis'*/
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DATABASE', 0),
],
],
.env
file , make sure you have something like below config in itREDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_DATABASE=0
The Food delivery Management (We are using laravel for this),this will be the main service handling the CRUD.
The Chat and notification service (NodeJS),this will handle everything notification, chat and live location update .Basically any realtime data.
mkdir {folder's name}
npm init -y
dotenv
expressjs
redis
redis-server
if you like to manage the server from your project https://www.npmjs.com/package/redis-server and nodemon
to run the script continously in development. Later in the article ,i'm going to discuss how PM2 library can be use to run our scripts continously in background and how we can manage /monitor logs.npm i expressjs redis redis-server dotenv
npm i nodemon -g
.env
file in the root folder with the following as its contents.NODE_SERVER_PORT=9016
server.js
with the following as contentconst http = require("http");
const express = require("express");
const app = express();
const cors = require("cors");
const redis = require("redis");
require("dotenv").config();
const { NODE_SERVER_PORT } = process.env;
//get port from env file
app.use(express.json());
const server = http.createServer(app);
server.listen(NODE_SERVER_PORT, function () {
console.log("server is running.");
});
We've implement socket connection in our nodejs (which i will do in one of my next articles) and in this implementation, will handled everything from chat message emiting to notifications and location data.
We don't want to connect our nodeJS to the database in which laravel will be connected to. (Infact no database).
Laravel service will be the only one that can perform database operations.
Both services can be subscriber ,publisher or even both.
Assuming every party of the application are on the app(online)
//import the class
use Illuminate\Support\Facades\Redis;
/*general is the channel/topic name ,this is what our nodejs service will subscribe to
second parameter is the whatever message object we want to send encoded into json string
*/
Redis::publish('general', json_encode(['type' => 'NewOrder','order'=>$order]));
NewFoodOrderedEvent
by running the command php artisan make:event NewFoodOrderedEvent
and php artisan make:listener NewFoodOrderedListener --event=NewFoodOrderedEvent
EventServiceProvider.php
use App\Listeners\NewFoodOrderedListener;
use App\Events\NewFoodOrderedEvent;
protected $listen = [
....,
NewFoodOrderedEvent::class => [
NewFoodOrderedListener::class ]
,...
];
NewFoodOrderedEvent.php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class NewFoodOrderedEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public $data
public function __construct($data)
{
$this->data=$data
//whatever data you passed to this event constructor
}
}
NewFoodOrderedListener.php
<?php
namespace App\Listeners;
//import the class
use Illuminate\Support\Facades\Redis;
use App\Events\NewFoodOrderedEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class NewFoodOrderedListener
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param NewFoodOrderedEvent $event
* @return void
*/
public function handle(NewFoodOrderedEvent $event)
{
//in here you can then publish to the nodeJS service
Redis::publish('general', json_encode($event->data));
}
}
$payload = ['type' => 'NewOrder','order'=>$order];
event(new NewFoodOrderedEvent($payload));
const http = require("http");
const express = require("express");
const app = express();
const cors = require("cors");
const redis = require("redis");
require("dotenv").config();
const { NODE_SERVER_PORT } = process.env;
//get port from env file
app.use(express.json());
//lets initialise the subscriber
const subscriber = redis.createClient();
//subscribe to general channel
subscriber.subscribe("general");
//now listen to whatever message is sent from laravel service
subscriber.on("message", function (channel, data) {
/*channel returns the channel's name in our case now general
and the data now will be the json string we encoded in the laravel.
This can be parse to js object using JSON.parse()
*/
}
const server = http.createServer(app);
//subscribe to general channel
server.listen(NODE_SERVER_PORT, function () {
console.log("server is running.");
});
NOTE:
if you need to subscribe and also publish in your nodejs, you will need to initialise two separate redis client one for subscribing and the other for publishing.One intialization cant be both subscriber and publisher.nodemon server.js
and also create a simple endpoint in the laravel that send the a get request to endpoint can trigger the event.basically call the event(new NewFoodOrderedEvent($payload));
in the endpoint implementation php artisan tinker
and create a mock order object and send by calling event(new NewFoodOrderedEvent($payload));
via tinker.redis-cli
and commandline and type MONITOR
to confirm.php artisan make:command SubscribeToGeneralChannel
then in the app/console/commands
folder , open the file and edit as below.<?php
namespace App\Console\Commands;
use App\Models\Order;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
class SubscribeToGeneralChannel extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'redis:subscribe-general';
/*
This is what will become the command we are going to use in terminal to subscribe our laravel service to nodejs
*/
/**
* The console command description.
*
* @var string
*/
protected $description = 'Subscribe to general channel';
/*description of the command ,this show in the laravel artisan help
*/
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
//general is the name of channel to subscribe to
Redis::subscribe(['general'], function ($message) {
//message in here is the data strring sent/publish from nodejs
$messageArray = json_decode($message, true);
//convert to php associative array
//lets echo the message we receive from node
echo $message;
});
}
}
const http = require("http");
const express = require("express");
const app = express();
const cors = require("cors");
const redis = require("redis");
require("dotenv").config();
const { NODE_SERVER_PORT } = process.env;
//get port from env file
app.use(express.json());
const publisher = redis.createClient();
const order = {
id:1
};
publisher.publish('general',JSON.stringify(order))'
//this will publish the order to all subscriber of the general channel which is laravel
/*//lets initialise the subscriber
const subscriber = redis.createClient();
//subscribe to general channel
subscriber.subscribe("general");
//now listen to whatever message is sent from laravel service
subscriber.on("message", function (channel, data) {
/*channel returns the channel's name in our case now general
and the data now will be the json string we encoded in the laravel.
This can be parse to js object using JSON.parse()
*/
}
const server = http.createServer(app);
//subscribe to general channel
server.listen(NODE_SERVER_PORT, function () {
console.log("server is running.");
});
php artisan redis:subscribe-general
(the custom command we created earlier) ,so you can inspect the message we echoed in our custom command immplementation.npm install pm2@latest
pm2 start server.js
pm2 status
that let you see list of all jobs.runlaravelsubscribetogeneralcommand.yml
nano runlaravelsubscribetogeneralcommand.yml
apps:
- name: runlaravelsubscribetogeneralcommand
script: artisan
exec_mode: fork
interpreter: php
instances: 1
args:
- redis:subscribe-general
redis:subscribe-general
in the code above is the custom command we created earlier.pm2 start runlaravelsubscribetogeneralcommand.yml
pm2 status
pm2 logs {indexofjob}
for example pm2 logs 0
php artisan redis:subscribe-general
directly or using a longer running process nohup nohup php artisan redis:subscribe-general --daemon &
.