How to loop every 3 minutes but script not sleep - php

I have a script for chat auto respond that uses while() to run, so it runs forever until it dies.
I want to be able to make it send a 'PING' message once every 3 minutes but still can do 'AUTO RESPOND' each message received.
The trouble is if i am using sleep(180) function for looping 'PING' message every 3 minute will make the 'AUTO RESPOND' every message be stop responding message because the script get sleep with sleep(180) function.
So what solution to make the script can do looping 'PING' message every 3 minutes but still can do 'AUTO RESPOND' every message at the same time.
What is possible ?
Did someone can help me with based on my script below ?
$this->connect();
while(!$this->isDisconnected()) {
$starts = $this->processUntil(array('message', 'session_start'));
foreach($starts as $go) {
switch($go[0]) {
case 'session_start':
$this->presence($status="Just Online !!!", $show="online");
break;
case 'message':
$filter = $show="online";
if($new['from'] == $filter) {
$sender = explode('#', $new['from']);
$this->message($new['from'], $body="AUTO RESPOND MESSAGE: Sorry $sender[0] Iam Not Here Right Now.", $type="chat");
}
$the_time = time();
$interval = 3*60;
while(true) {
if ($the_time + $interval >= time()) {
$this->message($myself, $body="PING !!!", $type="chat");
$the_time = time();
}
}
break;
}
}
}

Related

How to trigger an event in Laravel when nothing has been added to the database versus being alerted to when it has been updated?

I am building a simple auction solution on Laravel. The below code is some extract test code that is suppose to act as the auctioneer.
The problem is that when it's running it locks up access to the Auctionbid Postgres table and users can't bid while it's running. My testing is on localhost running a few users in auction as well as the auctioneer process all on same box/same IP<--might be making issue worse (not sure).
I've read all about the issues on SO about sleep(), downsides of polling and PHP sessions and have dug into Websockets a bit to see if I should go there. It also would also allow me to replace Pusher.
However, the issue I see is that an auction is all about timing and what events are NOT happening (if no bid in 3 seconds tell users "Fair Warning") and the Websocket implementations I've read about seem to be about what events ARE happening.
Questions:
Would a websockets implementation possibly be a solution? Every article I've looked at seems to be about the events that ARE happening. Maybe the classes on negative space are hindering my ability to see the solution :-)
Is having this all run on the same box/IP the issue? And/Or is sleep() just a bad way moving forward - as pointed out in at least 100 SO posts...
What are other possible solutions that allow me to check for what events are NOT happening?
public function RunTheAuction($auction_item_id, $auction_id)
{
set_time_limit(300);
$options = array(
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true
);
$pusher = new Pusher(
env('PUSHER_APP_KEY'),
env('PUSHER_APP_SECRET'),
env('PUSHER_APP_ID'),
$options
);
$bidIncrementResetCounter = 0;
$lastBidderId = 0;
$currentWinnerBidAmount = 0;
$lastBidderBidAmount = 0;
$count = 0;
while(true){
$auctionbid = Auctionbid::select('id', 'bid', 'bid_timestamp', 'auction_bidder_id')
->where('auction_item_id', '=', $auction_item_id)
->where('auction_id', '=', $auction_id)
->orderBy('bid', 'desc')
->orderBy('bid_timestamp', 'asc')
->first();
if ($auctionbid) { //there is a bid on the item
$currentWinnerId = $auctionbid->id;
$currentWinnerBidAmount = $auctionbid->bid;
if (($lastBidderId == $currentWinnerId) && ($lastBidderBidAmount == $currentWinnerBidAmount)) { //it's the same bidder
if ($bidIncrementResetCounter == 1) {
$message = "Fair Warning!";
$pusher->trigger('bids_channel', 'bid-warning', $message);
}
if ($bidIncrementResetCounter == 2) {
$message = "Going once... Going twice...";
$pusher->trigger('bids_channel', 'bid-warning', $message);
}
if ($bidIncrementResetCounter == 3) {
$message = "We have a winner!";
$pusher->trigger('bids_channel', 'bid-warning', $message);
break;
}
$bidIncrementResetCounter++;
} else {
$bidIncrementResetCounter = 0;
}
}
else{
$currentWinnerId = 0;
}
$lastBidderId = $currentWinnerId;
$lastBidderBidAmount = $currentWinnerBidAmount;
sleep(10); //<-----------------------------ISSUE
$count++;
if($count == 12){break;}
} //end loop
} //end function RunTheAuction

Sleep never continues execution

I have made a script that checks a server's availability.
The site was down and I was awaiting a fix(I was on call for a client and was awaiting a ticket from the provider), to limit calls I have used sleep():
$client = new \GuzzleHttp\Client();
$available = false;
date_default_timezone_set('doesntMatter');
//The server was more likely to respond after 5 AM, hence the decrese between intervals
$hours = array( //Minutes between calls based on current hour
0=>30,
1=>30,
2=>30,
3=>30,
4=>20,
5=>20,
6=>10,
7=>10,
8=>10
);
$lastResponse = null;
while(!$available) {
$time = time();
$hour = date('G', $time);
echo "\n Current hour ".$hour;
try {
$crawler = $client->request('GET', 'www.someSiteToCheck.com');
$available = true; //When the server returns a stus code of 200 available is set to TRUE
} catch (\GuzzleHttp\Exception\ServerException $e) {}
if(!$available) {
$secondsToSleep = $hours[$hour]*60;
echo "\n Sleeping for ".$secondsToSleep;
sleep($hours[$hour]*$secondsToSleep); //Sleep until the next request
} else {
exec('start ringtone.mp3'); //Blast my stereo to wake me up
}
}
Problem:
When I started the script it went in a 1800 second sleep and froze, it didn't re-execute anything
Given:
I tested my script with a sleep of 160 (for ex) and it made multiple calls
Checked my power settings so that the machine wouldn't go in stand-by
Checked error logs
(Even if obvious) I ran in CLI
Checked sleep() documentation for issues but nothing
Couldn't find anithing related
I think you have an error in your logic.
For example:
When it's 5AM
Then $secondsToSleep is 20*60 = 1200sec;
When you call the sleep function you multiply it again with 20
sleep($hours[$hour]*$secondsToSleep); => sleep(20*1200); => 24000sec => 6,66... hours
If you simply update your sleep parameter the result should be as expected.
if(!$available) {
$secondsToSleep = $hours[$hour]*60;
echo "\n Sleeping for ".$secondsToSleep;
sleep($secondsToSleep); //Sleep until the next request
}

call php function every 10mins for 1hour

got this code that should check if url is available and also give me ping:
<?php
function test ($url){
$starttime = microtime(true);
$valid = #fsockopen($url, 80, $errno, $errstr, 30);
$stoptime = microtime(true);
echo (round(($stoptime-$starttime)*1000)).' ms.';
if (!$valid) {
echo "Status - Failure";
} else {
echo "Status - Success";
}
}
test('google.com');
?>
How do i make it so this function would be called every lets say 10minues for 1hour (6times in total) ?
I would recommend you to make use of cron jobs if you are using a Unix server or Windows Task Scheduler in the case of windows.
Like this you will be able to use programmed tasks.
In the case of using cron you could do it easily like this:
*/10 * * * * php -f your_relative_or_full_path_URL/params > /dev/null
depends: do you want to do that just once?
Then you can call the function inside a loop and use sleep() after each execution of the loop.
Do you want to do it everyday? or one specific day each week/month? use a cron.
Use a simple for-loop and the sleep command:
for ($i = 0; $i < 6; $i++) { // Run the code 6 times
test($url);
sleep(10 * 60); // Sleep 10 Minutes
}
Send Email every day in a Month. I used it in daily backup mail..
<?php
ignore_user_abort(true); //if page is closed its make it live
for($i=0;$i<=30;$i++)
{
$to = "someone#exmple.com";
$subject = "Test mail $i";
$message = "Hello! This is a simple email message.";
$from = "from#example.com";
$headers = "From:" . $from;
mail($to,$subject,$message,$headers);
sleep(24*60);//send mail in every 24 hour.
}
?>

PHP waiting for correct response with cURL

I don't know how to make this.
There is an XML Api server and I'm getting contents with cURL; it works fine. Now I have to call the creditCardPreprocessors state. It has 'in progress state' too and PHP should wait until the progess is finished. I tried already with sleep and other ways, but I can't make it. This is a simplified example variation of what I tried:
function process_state($xml){
if($result = request($xml)){
// It'll return NULL on bad state for example
return $result;
}
sleep(3);
process_state($xml);
}
I know, this can be an infite loop but I've tried to add counting to exit if it reaches five; it won't exit, the server will hang up and I'll have 500 errors for minutes and Apache goes unreachable for that vhost.
EDIT:
Another example
$i = 0;
$card_state = false;
// We're gona assume now the request() turns back NULL if card state is processing TRUE if it's done
while(!$card_state && $i < 10){
$i++;
if($result = request('XML STUFF')){
$card_state = $result;
break;
}
sleep(2);
}
The recursive method you've defined could cause problems depending on the response timing you get back from the server. I think you'd want to use a while loop here. It keeps the requests serialized.
$returnable_responses = array('code1','code2','code3'); // the array of responses that you want the function to stop after receiving
$max_number_of_calls = 5; // or some number
$iterator = 0;
$result = NULL;
while(!in_array($result,$returnable_responses) && ($iterator < $max_number_of_calls)) {
$result = request($xml);
$iterator++;
}

Gearman with multiple servers and php workers

I'm having a problem with gearman workers running on multiple servers which i can't seem to solve.
The problem occurs when a worker server is taken offline, rather than the worker process being cancelled, and causes all other worker processes to error and fail.
Example with just 1 client and 2 workers -
Client:
$client = new GearmanClient ();
$client->addServer ('192.168.1.200');
$client->addServer ('192.168.1.201');
$job = $client->do ('generate_tile', serialize ($arrData));
Worker:
$worker = new GearmanWorker ();
$worker->addServer ('192.168.1.200');
$worker->addServer ('192.168.1.201');
$worker->addFunction ('generate_tile', 'generate_tile');
while (1)
{
if (!$worker->work ())
{
switch ($worker->returnCode ())
{
default:
echo "Error: " . $worker->returnCode () . ': ' . $worker->error () . "\n";
break;
}
}
}
function generate_tile ($job) { ... }
The worker code is being run on 2 separate servers. When every server is up and running both workers execute jobs as expected. When one of the worker processes is cancelled, the other worker executes all jobs as expected.
However, when the server with the cancelled worker process is shutdown and taken completely offline, requests to the client script hang and the remaining worker process does not pick up any jobs.
I get the following set of errors from the remaining worker process:
Error: 46: gearman_con_wait:timeout reached
Error: 46: gearman_con_wait:timeout reached
Error: 4: gearman_con_flush:write:110
Error: 46: gearman_con_wait:timeout reached
Error: 4: gearman_con_flush:write:113
Error: 4: gearman_con_flush:write:113
Error: 4: gearman_con_flush:write:113
....
When i start-up the other server, not starting the worker process on it, the remaining worker process immediately jumps into life and executes any remaining jobs.
It seems clear to me that i need some code in the worker process to cope with any servers that may be offline, however i cannot see how to do this.
Many thanks,
Andy
Our tests with multiple gearman servers shows that if the last server in the list (192.168.1.201 in your case) is taken down, the workers stop executing the way you are describing. (Also, the workers grab jobs from the last server. They process jobs on .200 only if on .201 there are no jobs).
It seems that this is a bug with the linked list in the gearman server, which is reported to be fixed multiple times, but with all available versions of gearman, the bug persist. Sorry, I know that's not a solution, but we had the same problem and didn't found a solution. (if someone can provide working solution for this problem, I agree to give large bounty)
Further to #Darhazer 's comment above. We found that as well and solved like thus :-
// Gearman workers show a strong preference for servers at the end of a list so randomize the order
$worker = new GearmanWorker();
$s2 = explode(",", Configure::read('workers.servers'));
shuffle($s2);
$servers = implode(",", $s2);
$worker->addServers($servers);
We run 6 to 10 workers at any time, and expire them after they've completed x requests.
I use this class, which keep track of which jobs work on which servers. It hasn't been thoroughly tested, just wrote it now. I've pasted an edited version, so there might be a typo or somesuch, but otherwise appears to solve the issue.
<?
class MyGearmanClient {
static $server = "server1,server2,server3";
static $server_array = false;
static $workingServers = false;
static $gmclient = false;
static $timeout = 5000;
static $defaultTimeout = 5000;
static function randomServer() {
return self::$server_array[rand(0, count(self::$server_array) -1)];
}
static function getServer($job = false) {
if (self::$server_array == false) {
self::$server_array = explode(",", self::$server);
self::$workingServers = array();
}
$serverList = array();
if ($job) {
if (array_key_exists($job, self::$workingServers)) {
foreach (self::$server_array as $server) {
if (array_key_exists($server, self::$workingServers[$job])) {
if (self::$workingServers[$job][$server]) {
$serverList[] = $server;
}
} else {
$serverList[] = $server;
}
}
if (count($serverList) == 0) {
# All servers have failed, need to insert all the servers again and retry.
$serverList = self::$workingServers[$job] = self::$server_array;
}
return $serverList[rand(0, count($serverList) - 1)];
} else {
return self::randomServer();
}
} else {
return self::randomServer();
}
}
static function serverWorked($server, $job) {
self::$workingServers[$job][$server] = $server;
}
static function serverFailed($server, $job) {
self::$workingServers[$job][$server] = false;
}
static function Connect($server = false, $job = false) {
if ($server) {
self::$server = self::getServer();
}
self::$gmclient= new GearmanClient();
self::$gmclient->setTimeout(self::$timeout);
# add the default job server
self::$gmclient->addServer($server = self::getServer($job));
return $server;
}
static function Destroy() {
self::$gmclient = false;
}
static function Client($name, $vars, $timeout = false) {
if (is_int($timeout)) {
self::$timeout = $timeout;
} else {
self::$timeout = self::$defaultTimeout;
}
do {
$server = self::Connect(false, $name);
$value = self::$gmclient->do($name, $vars);
$return_code = self::$gmclient->returnCode();
if (!$value) {
$error_message = self::$gmclient->error();
if ($return_code == 47) {
self::serverFailed($server, $name);
if (count(self::$server_array) > 1) {
// ADDED SINGLE SERVER LOOP AVOIDANCE // echo "Timeout on server $server, trying another server...\n";
continue;
} else {
return false;
}
}
echo "ERR: $error_message ($return_code)\n";
}
# printf("Worker has returned\n");
$short_value = substr($value, 0, 80);
switch ($return_code)
{
case GEARMAN_WORK_DATA:
echo "DATA: $short_value\n";
break;
case GEARMAN_SUCCESS:
self::serverWorked($server, $name);
break;
case GEARMAN_WORK_STATUS:
list($numerator, $denominator)= self::$gmclient->doStatus();
echo "Status: $numerator/$denominator\n";
break;
case GEARMAN_TIMEOUT:
// self::Connect();
// Fall through
default:
echo "ERR: $error_message " . self::$gmclient->error() . " ($return_code)\n";
break;
}
}
while($return_code != GEARMAN_SUCCESS);
$rv = unserialize($value);
return $rv["rv"];
}
}
# Example usage:
# $rv = MyGearmanClient::Client("Function", $args);
?>
since 'addServer' from gearman client is not working properly this code can choose a jobserver randomly and if fails try the next one, this way you can balance the load.
// job servers
$jobservers = array('192.168.1.1','192.168.1.2');
// prepare gearman client
$gmclient = new GearmanClient();
// shuffle job servers (deliver jobs equally by server)
shuffle($jobservers);
// add job servers
foreach($jobservers as $jobserver) {
// add random jobserver
$gmclient->addServer($jobserver);
// check server state if ok end foreach
if (#$gmclient->ping('ping')) break;
// if connections fails reset client
$gmclient = new GearmanClient();
}
Solution tested and working ok.
$client = new GearmanClient();
if(!$client->addServer("11.11.65.73",4730))
$client->addServer("11.11.65.79",4730);

Categories