Trying to make a dice-roll function in my telegram bot.
How it works right now:
When a user sends "roll" bot replies with sendDice method and sends another message with result like "you rolled 5, you won and blah-blah .."
> how it looks <
The problem is — the second message should not appear instantly, ideally after dice-roll animation is finished.
My first and obvious try on that was to add "sleep(3)" before sending the second message, and it worked fine, until I realized it completely delays the execution of my script for those 3 seconds. (if two users rolled at the same time, one of the users has to wait until another guy's roll will be finished). So it's not cool
What can I use? :c
The easiest option is to add the "task" to the "queue". The queue can be a table in the database with timestamps and chat id, when and to whom to send a message. Start another process, for example, which is started by cron, and it works for one minute. During that minute, he goes to the database and checks to see if there is something that needs to be sent now.
Crontab config
Open crontab
sudo crontab -e
Add next string
* * * * * php /path/to/cron.php >> /path/to/log/file/for/debug.log 2>&1
Cron run your script every 1 minute.
Cron.php "live" 60 second
cron.php:
$now = time();
$expectedTime = $now + 60;
while (true) {
Worker::run();
if ($expectedTime < time()) {
die(0);
}
}
Where Worker::run() your method, which get records from db, check timestamp and send message
From Wikipedia:
In computing, [..] fork is an operation whereby a process creates a
copy of itself.
When your PHP script runs, you can create multiple processes that interact with each other. Those processes run concurrently and asynchronous. This way you can have one process waiting to send the message, while the rest of the script continues to run.
Instead of starting another process, you could also start another thread. The technical difference between the two is explained here:
Forking vs Threading
PHP offers Process Control Extensions for both forking and threading. You might want to check out the example in the PHP documentation for pcntl_fork().
Depending on your needs, you might want to use a framework designed to handle concurrency throughout your application. If that is the case, I would recommend amphp.
Related
put in simple words:
i am writing php scripts which send and receive sms,
scripts will calculate to send users campaign SMS every week based on each user registration date, for example every monday 10 AM send sms to mr. A and every friday at 7 pm sends sms to miss B..
and php scripts will take care of everything needed ..
problem : obviously a very funny way is to have someone refresh the main page of my application every some seconds or so to be able to continue to calculate and understand what and when to do jobs, or have the main page always open on my computer so javascripts and jquery will handle the rest!
My Question : how can i have my php program or scripts to be something like awake without need to someone refreshes or have open the main page? by awake i mean like it senses the next schadule and executes it and so on ..
some raw ideas to answer : perhaps i could call the main page using ajax or curl every 10 seconds .. but i don't know how to awake ajax or curl in first place ..
i see some internet posts suggest something like command line either in linux unix or windows .. but i usually access the host not the command line is it right ? or command line is something in host and i don't know it, if so please help me ..
important example : there are php wp plugins like total cache and supper cache which seem to be always on and awake of schedules without need of somebody refreshing a page ..
please give answers all in php and php families if possible, i don't know unix or those kind of programmings at all ..
------- accourding to answers made some progress to question ..
now i have this bellow script :
ignore_user_abort(true);
set_time_limit(0);
$data = file_get_contents('filename.txt');
$data = $data+1;
file_put_contents('filename.txt', $data);
$page = $_SERVER['PHP_SELF'];
$sec = "4";
header("Refresh: $sec; url=$page");
it works! even when i restart the local host . main problem is now when i closed the main page it stopped incrementing in filename.txt and when reoppend the page two instance where running the increment continued so :
should'nt it continue to increment even when i close the page ?
and how i stop it ?
and is it normal to have more than one instance of the page run in background?
finally : according to instructions on this page it's best i create a starter or reload page then use commands to initiate this reload page for example every 1 minute and then write PHPs like normal ..
last not least : how to stop this background script ? for update or maintenance ..
For this particular issue cron jobs have been invented. Cron jobs are timed jobs that can for example execute a PHP script.
You could set up a cron job to check which user should receive his/her sms every hour. Depending on your operating system you can set up these cron jobs. For linux distrubutions there are tons of guides on how to set this up.
From Wikipedia:
The software utility Cron is a time-based job scheduler in Unix-like computer operating systems. People who set up and maintain software environments use cron to schedule jobs (commands or shell scripts) to run periodically at fixed times, dates, or intervals. It typically automates system maintenance or administration—though its general-purpose nature makes it useful for things like downloading files from the Internet and downloading email at regular intervals. The origin of the name cron is from the Greek word for time, χρόνος (chronos). (Ken Thompson, author of cron, has confirmed this in a private communication with Brian Kernighan.)
I have added a resource explaining how to use cron jobs.
An alternative method is to keep a PHP script running in the background:
// Keep executing even if you close your browser
ignore_user_abort(true);
// Execute for an unlimited timespan
set_time_limit(0);
// Loop infinitely
// If you create a file called stop.txt,
// The script will stop executing
while (!file_exists('stop.txt')) {
// Retrieve user data and sens sms messages
// Wait for an hour
sleep(3600);
}
Update
ignore_user_abort(true);
set_time_limit(0);
$data = file_get_contents('filename.txt');
while (!file_exists('stop.txt')) {
// Add 1 to $data
$data = $data+1;
// Update file
file_put_contents('filename.txt', $data);
// Wait 4 seconds
sleep(4);
}
To stop executing create a file called stop.txt
Resources
About Cron jobs
You can create cron jobs in almost all servers without accessing command prompt.
Cron job can be used to initialize php scripts in cli at specified intervals lik every minute, every hour etc
This question already has answers here:
Schedule and execute a PHP script automatically
(7 answers)
Closed 9 years ago.
I am developing a web app which requires events. The user creates an event at a specific time, and I need a script to be executed and activate the event at the exact time, so the event can start.
Any ideas on how I can do this? I googled and searched through stack overflow, but all I encountered was multiple execution at specific time. What I need is execution at automatically set time.
Hope you help me, I'm desperate.
You have 3 options. My recommendation: Use cron if you can, user driven if you have to, and daemon as a last resort.
(1) cron (as mentioned in comments)
cron is a scheduler for linux systems that will run a command line job on your system. You log into your server over ssh, type crontab -e, and add a line like this:
4 5 * * * php /path/to/my/script.php
This would run the script at 5:04 a.m. every day.
<?php
// /path/to/my/script.php
// Do something
Some hosting services allow entering cron jobs with a GUI. There are also external cron services, that will call a URL for you at specific times.
(2) daemon
This is the most advanced option and also the least reliable: You run a command line script that contains an infinite loop. The script then periodically checks state and responds to it. Because it is likely to crash after months of running, you have to have a second script to restart it in case it does. This is a lot of work, but it is the most flexible approach.
<?php
while (1) {
// fetch $last_exec_timestamp from database
if ($last_exec_timestamp < time() + 86400) {
// set last_exec_timestamp to now in database
// do something
}
sleep(5);
}
3. user driven
If you have a decent amount of traffic on your site, you can simply include a the job this in your page footer, when there is no more output. Make sure this code is fast, or an unlucky user will be waiting for it.
<?php
// fetch $last_exec_timestamp from database
if ($last_exec_timestamp < time() + 86400) {
// set last_exec_timestamp to now in database
// do something
}
There are also to more fancy approaches of "user driven" that I haven't personally tested in another stack overflow question.
What u are looking for is CRON JOBS
http://net.tutsplus.com/tutorials/php/managing-cron-jobs-with-php-2/
I have a website in PHP and users can schedule message to be sent. I can sent message with command similar to this one:
php sendMsg.php 249
where number is ID of the message
Many people suggested to use cron jobs, but since I don't want to run this in interval cron is no option(only once - for example after 3 hours).
My idea was as follows:
$seconds = $hours*60*60;
exec('sleep '.$seconds.'; php sendMsg.php 249');
But this wont work because it will block php for further executing. What is the simplest way to achieve this?
You said you don't want to use a cron job because you only want the message sent once, but this is mis-understanding the way that a cron job would be written for this kind of task
Consider a situation where you have many users creating many messages to be sent at various given points in time.
You don't want to have a PHP program sitting running on your server all that time for each of those messages; it would be wasteful of server resources, even if they were all just sleep()ing for the duration.
Instead, one would use a cron job to run a short-lived PHP program once every minute (or whatever interval suits you).
Your message creation program would not be written to acually send the message; instead it would insert it into a database, along with the time it needs to be sent.
Meanwhile, the cronjob PHP program would scan this database every minute to see if there are any messages that are due to send but have not yet been sent. It would then send those messages and mark them as 'sent' on the DB.
This is the standard way to write this kind of thing, so it's not surprising that people are recommending it to you.
Doing it this way means that you never have a program running on your system for longer than necessary. Both PHP programs do their job quickly and exit, meaning that no-one is kept waiting for them.
It also makes it much more robust. Imagine if your server had to be rebooted. If you had a bunch of PHP programs running for hours waiting for their moment to send their message, they'd all be lost. On the other hand, if they had saved their message to a DB, the cron job would find them and send them correctly once the server was restarted.
Put the schedule in a database. Run a cronjob every minute or so, check the database if a message should be sent within this minute, and send it.
Is there a reason you don't want to use a cron job? That would be the simplest and most efficient way of sending the messages.
I would think that a cronjob ist still the right way
Create a table where the to be send messages are stored, with a timestamp when to be send and a flag for isSend
Create a cronjob - start php skript every 1 minute , which sends the messages with timestamp < current time and isSend = false
Ignore suggestions of cron, if you want to simply wait a period of time then use the at scheduler:
$hours = 2;
$command = sprintf('echo "php sendMsg.php 249" | at now + %d hours', $hours);
exec($command);
I'm making a PHP site, and I would like to have a script (when you click a button) which adds some info to my MySQL database (I can do this part by myself) and it executes a script 5 minutes later. Maybe it's not difficult, but it's hard to google stuff like this.
Sleep is a VERY bad idea. Client browser would have to wait 5 minutes to finish request!!!
In my opinion it's not possible to do it like you want to.
You should create another script which queries database and checks if there is new data (and on successful fetch does the job). This script should be run by cron every N minutes.
Pretty tough one.
I'd go for something like this:
your original script adds a record to the database, containing its time of execution,
another script contains the action that needs to be taken 5 minutes later - but launches it only if the db record mentioned above contains a timestamp of at least 5 minues ago (hope that's clear enough, I'm having trouble phrasing this)
set crontab to execute the second script every X minutes (perhaps 2).
It won't be 5 minutes EXACTLY, but rather something between 5 and 7 (in case you choose to launch the script every 2 minutes). Would that do?
You could implement a queue in your database, where you add "commands" to be executed, and also store when to execute this command. Then have a cron job that runs every minute and checks said queue to see if it's time to execute a certain command.
If you're on a unix box:
exec("echo 'php script.php' | at now +5 minutes");
Which will schedule the php script.php command to run after 5 minutes.
I'm making a browser-based game and I want it to if someone wants to build a building it takes * minutes and then finishes.
Considering this is your actual goal, I recommend just saving the original building with a timestamp.
I know you tagged your question with PHP, but I don't want to include all the overhead of handling mysql queries in PHP, especially since I don't know how you prefer to execute the queries or what framework you're suing, so here's some pseudocode to handle this "building buildings" task:
build.php
building_type_id = sanitize(POST['id'])
user_id = current_user['id']
query('INSERT INTO buildings (user_id, building_type_id, created_at)
VALUES (' + user_id + ', ' + building_type_id + ', CURRENT_TIME)');
my_buildings.php
user_id = current_user['id']
completed_buildings = query('SELECT * FROM buildings b
LEFT OUTER JOIN building_types t ON b.building_type_id = t.id
WHERE DATE_ADD(b.created_at, INTERVAL t.construction_time SECOND) < NOW();')
under_construction = query('SELECT * FROM buildings b
LEFT OUTER JOIN building_types t ON b.building_type_id = t.id
WHERE DATE_ADD(b.created_at, INTERVAL t.construction_time SECOND) > NOW();')
Hope this helps!
IMHO the best way is: On button click save the job to run in the db with the time it should run. Write a small daemon, fetches every 10/5/2 seconds new jobs which should be executed and executes them.
EDIT: Btw the idea using cron for checking for new jobs to execute, is better, but only if you have a small website and you don't need to do load balancing for the jobs.
The way I would do this is to run a cron job between the two scripts.
the first script sets a value in a database table.
the cron job executes the second script. every minute or what not.
the second script checks for the database value set by script 1 to decide whether to run entirely or not.
I would suggest doing the timer in Javascript rather than PHP.
Put a timestamp in the user's $_SESSION to indicate when they started the event, and then have Javascript call back to the browser after five minutes.
PHP would still need to know the start time (to prevent the user from hacking the game by tweaking the Javascript time-out), but it wouldn't need to actually do any count-down timing or sleeping or anything like that itself.
You could fork the process and in the child fork, do a sleep for 5 minutes before executing your second script. I've tested this and it appears the child process will still execute even after the parent has finished. Something like
//initial code
$pid = pcntl_fork(); //fork the process
if ($pid==0) // if in the child
{
exec("sleep 300; php second_process.php"); //sleep for 5 minutes and execute second script
return; // or exit
}
// rest of initial script...
The "return;" is important as the rest of the script will execute a 2nd time (i.e. in the child) unless it's there.
Someone asked about the purpose of this and your answer was:
"I'm making a browser-based game and I want it to if someone wants to build a building it takes * minutes and then finishes"
You don't actually need to time an execution for this. You can do it all in one run by storing buildStartedAt and buildFinishedAt as part of the building-schema.
Now maybe you want the building to have a nice animation when it finishes, then you just do all of that on the frontend but make sure nothing meaningful can be done with the building if the timestamp is before the buildFinishedAt time in order to a void cheating by potential hackers.
Are you looking for that?
sleep php.net
I have this mail script I have to run a few times.
To start the script I will use cron, but the script has to run 2 or 3 more times (with an hour apart).
What's the best way to do this?
To use the sleep command for an hour, or at the end of the script, place some code, so that the script will create a new cron job to run it self after an hour?
Thanks
Unless there's some cost savings in keeping the script running in memory, you're better off using cron to invoke it every hour, as needed.
0 0-2 * * * /usr/local/bin/mail-script.php
You can choose multiple hours using the - syntax, or the comma syntax:
0 0,1,2,3 * * * /usr/local/bin/mail-script.php
If it needs to maintain some form of state, use a temporary file to keep saved state.
Do:
> man 5 crontab
To see if your *nix handles the above cases.
Finally, unless you know the script has to run only 2-3 times, you're better off putting the logic about whether to "run or not to run" in the PHP script itself, and then just run it every hour.
One advantage of using sleep() is that it could be more portable. For example, on many systems I work with, users are not allowed to have their own cron jobs - so writing your program to take care of its own timer-ness might be an advantage.
An alternative to sleep() might be using SIGALRM (so your script catches an interrupt and executes code at a certain interval - when that interrupt is thrown.)
I mean, I'd recommend using cron - but here are some alternatives!
I'm not sure either approach (sleeping for an hour, or creating cron jobs from php) is ideal, how about a cron job that runs every hour anyway, then your php script checks whether it should run?
Why not just set the cron criteria so it fires those specific times? Cron is pretty flexible in that aspect.
Update your question with when you want it to fire off and I can give an example.