Need support about BLPOP Predis PHP - php

I am building chat message system long poll use BLPOP.
I used Predis PHP. When I run test/get ->it runs okie with 30s timeout.
While running test/get I try to push data by test/push but it has problem. Push not execute immediately unless test/get finished. test/push takes 30s.
I use command line to push data: RPUSH message:test hello -> It executes immediately and very nice.
require './vendor/autoload.php';
class Test extends CI_Controller {
public $keyChat = 'message:test';
public function __construct() {
parent::__construct();
}
public function push() {
$redis = new Predis\Client(['host' => 'localhost','port' => 6379]);
$redis->rpush($this->keyChat, 'hello you');
$redis->expire($this->keyChat, 3600);
echo "send message success";
}
public function get() {
$redis = new Predis\Client(['host' => '127.0.0.1','port' => 6379]);
$res = $redis->blpop($this->keyChat, 30);
var_dump($res);
}
}

If you checked the BLPOP documentation, you will find that it is a blocking operation, I suppose that you are trying to push by instantiating another Redis client, so BLPOP can find the value and return it.
The 30 seconds issue, is the timeout for BLPOP to unblock as in:
$redis->blpop($this->keyChat, 30);
The reason it works when you push it from the command line, is that it is a different connection, I am not sure in the case of Predis, but I think the same connection is returned when you try to RPUSH , that is why it is giving you that issue.

Related

How to keep the code running after return the response early?

I need to save the request into the database after that i have to call an API to sync the data to the other server.
i do the API call using the finally but it seems PHP still processing it, even when i am sending the response in the try clause.
how do i make this asynchronous ? i want to send the response as fast as possible but still processing the API call after the response.
so this what the simple code look like, describing what i am currently doing.
Code with finally =>
public function store(Request $request)
{
try {
//returning the code early
return response("i am speed", 202);
} catch (\Throwable $th) {
return response($th->getMessage(), 500);
} finally {
//lets says this is the super long too run
$i = 0;
$last = 11111111;
while ($i <= $last) {
$i++;
}
}
}
//this code finish in 1000ms
code without finally =>
public function store(Request $request)
{
try {
return response("i am speed", 202);
} catch (\Throwable $th) {
return response($th->getMessage(), 500);
}
} //this code finish in 90ms;
why this is happen ?
i already sending the response but why it not returning early ?
what can i do to send the response first then continue the execution ?
I already finish this problem.
As the comment suggest Laravel have a feature called a queue that will dispatch the job the database, this process won't running until you run the queue worker.
To make queue what i do is :
First change the .env QUEUE_CONNECTION to database.
QUEUE_CONNECTION=database
Then run this artisan command to setup the queue worker.
php artisan queue:table
php artisan migrate
After that make a job for the function that want to run in the queue.
For example i am gonna put the finally code (the one in the question) in the new job.
php artisan make:job exampleJobName
Then go to exampleJobName.php, write the code that will be running in the queue in the handle function.
public function handle()
{
//lets says this is the super long too run code
$i = 0;
$last = $this->data; //variable from constructor
while ($i <= $last) {
$i++;
}
}
//exampleJobName.php
If a variable need to be pass to the handle, then add a contructor in the __construct function.
public function __construct($data)
{
$this->data = $data;
}
//still inside the exampleJobName.php
Then everything is setup go to the controller that want to run this job (i am gonna take example from question) and change the code to this.
public function store(Request $request)
{
try {
$data = 111111111;
exampleJobName::dispatch($data);
//this will insert the job on the jobs table in the database
//therefore the job won't run until the queue worker is running
return response("i am speed", 202);
} catch (\Throwable $th) {
return response($th->getMessage(), 500);
}
}
//this code finish fast
Everything is ready then just run the queue worker in the terminal side by side with artisan serve.
php artisan queue:work
The queue worker will check to the jobs table if there are any job that hasn't run yet. then will run it one by one.
That's what i do, hope this can help someone.
credit to Tim Lewis in the comment for show me this this link.
Call an API to sync the data to the other server potentially can take a long time so I suggest that you create and dispatch a job for that.
If you still want to do so right after the response is sent, you might want to use dispatchAfterResponse.

Laravel queue keep processing multiple times for a job

Below is what's happening when i run php artisan queue:listen and at my job table only have one job
and this is my code :
public function handle(Xero $xero)
{
$this->getAndCreateXeroSnapshotID();
$this->importInvoices($xero);
$this->importBankTransaction($xero);
$this->importBankStatement($xero);
$this->importBalanceSheet($xero);
$this->importProfitAndLoss($xero);
}
In order for a job to leave the queue, it must reach the end of the handle function -- without errors and exceptions.
There must be something breaking inside one or more of your functions.
If an exception is thrown while the job is being processed, the job will automatically be released back onto the queue so it may be attempted again. https://laravel.com/docs/5.8/queues
The same behavior can be achieved with
$this->release()
If you can't figure out what is breaking, you can set your job to run only once. If an error is thrown, the job will be considered failed and will be put in the failed jobs queue.
The maximum number of attempts is defined by the --tries switch used
on the queue:work Artisan command. https://laravel.com/docs/5.8/queues
php artisan queue:work --tries=1
If you are using the database queue, (awesome for debugging) run this command to create the failed queue table
php artisan queue:failed
Finally, to find out what is wrong with your code. You can catch and log the error.
public function handle(Xero $xero)
{
try{
$this->getAndCreateXeroSnapshotID();
$this->importInvoices($xero);
$this->importBankTransaction($xero);
$this->importBankStatement($xero);
$this->importBalanceSheet($xero);
$this->importProfitAndLoss($xero);
}catch(\Exception $e){
Log::error($e->getMessage());
}
}
You could also set your error log channel to be slack, bugsnag or whatever. Just be sure to check it. Please don't be offended, it's normal to screw up when dealing with laravel queues. How do you think I got here?
Laravel try to run the job again and again.
php artisan queue:work --tries=3
Upper command will only try to run the jobs 3 times.
Hope this helps
In my case the problem was the payload, I've created the variable private, but it needs to by protected.
class EventJob implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
// payload
protected $command;
// Maximum tries of this event
public $tries = 5;
public function __construct(CommandInterface $command)
{
$this->command = $command;
}
public function handle()
{
$event = I_Event::create([
'event_type_id' => $command->getEventTypeId(),
'sender_url' => $command->getSenderUrl(),
'sender_ip' => $command->getSenderIp()
]);
return $event;
}
}
The solution that worked for me to delete the job after pushing them into the queue.
Consider the e.g.
class SomeController extends Controller{
public function uploadProductCsv(){
//process file here and push the code inot Queue
Queue::push('SomeController#processFile', $someDataArray);
}
public function processFile($job, $data){
//logic to process the data
$job->delete(); //after complete the process delete the job
}
}
Note: This is implemented for laravel 4.2

Using reactive PHP in a blocking application

I'm currently working on a PHP application that will be using some websocket connections to talk to another service.
To talk to this websocket service, we are using Ratchet - which is a PHP library based on react PHP.
This piece of code needs to send and respond to a couple of requests, and after that, should return the information to the "main thread".
Example flow:
HTTP request -> controller -> Starts a service which opens a websocket client -> websocket client is talking to server -> once its done it should return the outcome to the controller code -> controller outputs to user
The issue I'm having is that I'm not familiar with Reactive PHP and am not sure how to handle this.
I've tried;
$service = new WebsocketService();
$startTimer = time();
$service->getList(44);
while($service->getResponse() == null) {
usleep(500);
if (time() > $startTimer + 10) {
continue; //Timeout on 10 seconds
}
}
var_dump($service->getResponse());
The service code would set its "response" variable to something other than null once its done. This obviously fails, because the sleep method is blocking the thread. Also without, it seems like the while loop is blocking I/O and the reactive code fails.
A solution would be to open up a new thread and run the websocket code there, but I wouldn't be happy with that.
I feel like I need to implement some sort of "watcher" around the websocket process, but I'm not sure how to do that.
Our Websocket service client code looks like this;
private $response = null;
/**
* #return null|object
*/
public function getResponse() {
return $this->response;
}
public function getList($accountId) {
$this->response = null;
\Ratchet\Client\connect('ws://192.168.56.1:8080')->then(function(\Ratchet\Client\WebSocket $conn) use ($accountId) {
$login = new \stdClass();
$login->action = 'login';
$conn->on('message', function($msg) use ($conn, $login, $accountId) {
try {
$response = json_decode($msg);
if ($response->result_id == 100) {
//Succesfully logged in to websocket server
//Do our request now.
$message = new \stdClass();
$message->target = 'test';
$conn->send(json_encode($message));
}
if (isset($response->reply) && $response->reply == 'list') {
$this->response = $response; //This is the content I need returned in the controller
$conn->close(); //Dont need it anymore
}
} catch (\Exception $e) {
echo 'response exception!';
//Do nothing for now
}
});
$conn->send(json_encode($login));
}, function ($e) {
echo "Could not connect: {$e->getMessage()}\n";
});
}
Running the code like this also does not work;
$service = new WebsocketService();
$service->getList(44);
echo 'Test';
var_dump($service->getResponse());
because the "test" echo comes before I even get a response from the websocket server.
Please, enlighten me! I'm not sure what to search for.
PHP and websockets still seem to be a bit experimental. Nevertheless I have found a great tutorial on medium.com, written by Adam Winnipass which should be really helpful for solving your problem: https://medium.com/#winni4eva/php-websockets-with-ratchet-5e76bacd7548
The only difference is that they are implementing their websocket client with JavaScript instead of PHP. But in the end there should not be much of a difference, because as soon as we have opened the Websocket connection of each end both applications have to send and also wait to receive notifications - this is how they illustrate it:
Seems like one possibility to create a successful Websocket connection is to extend the MessageComponentInterface
use Ratchet\MessageComponentInterface;
which also requires
use Ratchet\ConnectionInterface;
The message component interface defines the following methods:
onOpen
onMessage
onClose
onError
And I think this is how the Ratchet library is implementing it. This is how they are finally starting their server:
use Ratchet\Server\IoServer;
use MyApp\MyCustomMessageComponentInterface;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new MyCustomMessageComponentInterface()
)
),
8080
);
$server->run();
With this architecture you already can receive (onMessage) and sending is also possible with the send() method.
I can not solve the exact problem with your existing code. But I guess if you are using the pre-built classes and interfaces of the library as intended (and demonstrated here) you should be able to achieve what you want by adding your code to the corresponding methods.
More information and examples can be found in the docs:
http://socketo.me/docs/server
http://socketo.me/api/namespace-Ratchet.html
Are you extending class with WsServer, This might be issue, if you are getting fatal errors. I am not sure whether you are getting fatal errors or warnings. Also i notice the public function onOpen() opens a connection. Please try referring this document http://socketo.me/api/class-Ratchet.WebSocket.WsServer.html might be useful.

PHP parallel/asynchronous SSH connections

I'm trying to open multiple connections (various devices) to run a command and get the output.
The problem is that i have to run them "all at once"/parallel.
If i wait for one result and then to run the other one it takes way too long
and with a large number of devices that can go very bad.
I'm also using curl which I know that there is curl_multi and I was wondering if there was something similar with SSH for php.
I'm using Net_SSH2 for now.
You'll need to use two PHP libraries: https://robo.li/tasks/Remote/#ssh and https://github.com/cheprasov/php-parallel. Your class method might be something similar to the example below:
function runParallelSSH() {
$parallel = new Parallel(new ApcuStorage());
foreach ($credentials as $user => $host) {
$connection = sprintf('%s#%s', $user, $host);
$connections[] = $connection;
$Parallel->run($connection, function() {
$gitTask = $this->taskGitStack()
->checkout('master')
->pull();
});
}
$results = $parallel->wait($connections);
}
Without using thirdparties like curl_multi you have to use PHP multithreading, for this you need an extension pthreads.
Look in the docs for PHP threading
The most interesting feature is using it like this (code modified from PHP.net)
class My extends Thread {
public function run() {
//curl_exec whatever
}
}
$my = new My();
//start as many as you need
$my->start();
//wait for the threads to finnish and join one thread at a time with main-process-thread:
var_dump($my->join());:
Good Luck!

PHP Cli key event listener function

I am making php cli application in which I need Key Event listener
let's say this is my code
Task To do
for($i=0;$i<=n;$i++){
$message->send($user[$i]);
}
Once I'm done with sending messages, I will have to keep connection alive with following code to receive delivery receipts.
I use $command = fopen ("php://stdin","r"); to receive user commands.
while(true){
$connection->refresh();
}
Connection is automatically kept alive during any activities but on idle i have to keep above loop running.
How can I run the event on pressing any key which will make this event break and execute some function?
PHP is not developed, to handle this kind of problems. The Magic Word would be Thread
The Cleanest way, I can Imagine, is taking a look into the Extension PThreads. With it, you can do Threads like in other Language:
class AsyncOperation extends Thread {
public function __construct($arg){
$this->arg = $arg;
}
public function run(){
if($this->arg){
printf("Hello %s\n", $this->arg);
}
}
}
$thread = new AsyncOperation("World");
if($thread->start())
$thread->join();
The other way would be to do tasks via a queue in a different script. There are some Queue Server out there, but it can be done simple calling shell_execute your Queue Script via PHP.exe. On Linux you need something like ...script.php > /dev/null 2>/dev/null &, Windows start /B php..., to stop waiting on Script is finished.

Categories