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
Related
I'm currently working on a browser game with a PHP backend that needs to perform certain checks at specific, changing points in the future. Cron jobs don't really cut it for me as I need precision at the level of seconds. Here's some background information:
The game is multiplayer and turn-based
On creation of a game room the game creator can specify the maximum amount of time taken per action (30 seconds - 24 hours)
Once a player performs an action, they should only have the specified amount of time to perform the next, or the turn goes to the player next in line.
For obvious reasons I can't just keep track of time through Javascript, as this would be far too easy to manipulate. I also can't schedule a cron job every minute as it may be up to 30 seconds late.
What would be the most efficient way to tackle this problem? I can't imagine querying a database every second would be very server-friendly, but it is the direction I am currently leaning towards[1].
Any help or feedback would be much appreciated!
[1]:
A user makes a move
A PHP function is called that sets 'switchTurnTime' in the MySQL table's game row to 'TIMESTAMP'
A PHP script that is always running in the background queries the table for any games where the 'switchTurnTime' has passed, switches the turn and resets the time.
You can always use a queue or daemon. This only works if you have shell access to the server.
https://stackoverflow.com/a/858924/890975
Every time you need an action to occur at a specific time, add it to a queue with a delay. I've used beanstalkd with varying levels of success.
You have lots of options this way. Here's two examples with 6 second intervals:
Use a cron job every minute to add 10 jobs, each with a delay of 6 seconds
Write a simple PHP script that runs in the background (daemon) to adds an a new job to the queue every 6 seconds
I'm going with the following approach for now, since it seems to be the easiest to implement and test, as well as deploy on different kinds of servers/ hosting, while still acting reliably.
Set up a cron job to run a PHP script every minute.
Within that script, first do a query to find candidates that will have their endtime within this minute.
Start a while-loop, that runs until 59 seconds have passed.
Inside this loop, check the remianing time for each candidate.
If teh time limit has passed, do another query on that specific candidate to ensure the endtime hasn't changed.
If it has, re-add it to the candidates queue as nescessary. If not, act accordingly (in my case: switch the turn to the next player).
Hope this will help somebody in the future, cheers!
I need some advice on the best way to do this. I am developing a web application that monitors a data stream and adds that to a database. It then checks it against a ruleset for specific criteria. If one of these criteria is met, it needs to run a specific query on that same entry x minutes later. (x is set by user config).
I was thinking a way to do it would be to have it create cron jobs but first, I don't know how to do that, secondly, I was wondering if there is a better way.
Entry received -> Matches criteria -> Wait X minutes -> Execute another query.
I need it to do this without pausing the script because lots of data would be coming in so if it waited for 10 minutes it wouldn't ever process all the data.
Thanks!
If there are many similar tasks like this, you can make a table for tasks and populate it when needed.
Then, cron script that runs every minute can select all entries from this table with execution time less or equal than current time and run them.
Don't create multiple cron jobs.
Store the users configuration as a timestamp (in the future), and have one cron job that runs frequently (every 1 minute is the maximum) and will query the list of user configurations to see if another query needs to be executed.
Store the last execution time of the cron job and have it query the list -
SELECT * FROM `pending_queries` WHERE `execution_ts` <= {$last_execution_ts}
A word of warning
Should some of the queries take a longer time to execute, you run the risk of potentially overlapping the execution time of one or more queries. To solve this, as soon as you extract data on a pending query, you should mark it with an is_processing flag as some other field in the row. So your query now becomes-
SELECT * FROM `pending_queries` WHERE
`execution_ts` <= {$last_Execution_ts} AND `is_processing`=0
Finally, after processing a query, you should delete it from the pending_queries table.
First and easiest way:
Learn cronjob.
Second way:
If you want to wait for 10 minutes without stopping the script execution, the user will have to wait 10 mins.
If you want to do this operation without bothering the user, you can create a child process that will handle this operation. The process won't stop but interaction with the user will be end. In the child process you can pause the script for 10 mins.
How to create a child process: http://php.net/manual/en/function.pcntl-fork.php
How to pause the process: http://php.net/manual/en/function.sleep.php
I solved similar problem for myself using JS/JQuery and PHP. Here is kind of pseudo code for it:
pingTimer = 0;
function pingTimerIncrement() {
//your criterias to be checked here either using plain
//JS or AJAX to do it on server side
if (criterias met) {
pingTimer += 1; //increase by 1 minute
if (pingTimer == YOUR_USER_CONFIG_MINUTES) {
//code to update your database using ajax
}
}
}
$(function() {
var timerInterval = setInterval("pingTimerIncrement()", 6000); //1 minute
});
the other way if you dont want to use JS/JQuery then use cronjob
I am trying to create a site in PHP and MySQL where a person is assigned to do a task for another person. Time period allotted to complete the task is 72 hours.
If done, the other person will confirm so. If not, I want to take certain actions (like blocking his account, sending an email, assign the task to someone else etc.) What is the best way to do this?
As the count-down runs second-by-second, I guess I will have to run a script every second.
You could use a cronjob to check for the deadline and eventually send the email, block the account, etc...
Although, if you actually need a persecond precision, you might want to use a single process with an "infinite" cicle and some sleeps in between.
If your server is from *nix family, you could use cron/crontab. See examples of usage at: http://en.wikipedia.org/wiki/Cron and https://help.ubuntu.com/community/CronHowto
Very few things have to happen truely immediately. If you've waited 72 hours for something to happen, having an action occur within a matter of a few minutes will not matter so much.
If you really do want something to happen so quickly, and you will always have a long time between potential events, one thing I would suggest is not using a cronjob, but something more akin to what #muc has suggested - a script that runs regularly within a shell script that will keep it going (just doing an 'exec $0' at the end to rerun the script when it would exit).
The script (in PHP for example) that checks the database doesn't have to be running all the time either. Whenever it finds something that is due to happen in more than a few seconds time, it sleeps till the next event is due to happen. When it wakes up, it can double-check that it is still required, and then performs the relevant job.
<?php
$jobId = whatToRunNext();
if (! $jobId) {
exit;
}
$secsToNextJob = howLongToNextJob($jobId);
if ($secsToNextJob > 0) {
sleep($secsToNextJob);
if (! jobStillRequired($jobId)) {
exit;
}
}
doJob($jobId);
exit;
Wrap that in a shell sript that will keep it running, maybe with a small sleep in the bash script, and you'd be good - while not being in a very long-running, cpu-killing loop.
If I needed to do something like that, I would probably go by these steps:
Create event and calculate deadline
Set up a cronjob to run at the deadline time
cronjob checks the event status and takes actions
I think this will be the most efficient way in doing it.
I am trying to create a site in PHP and MySQL where a person is
assigned to do a task for another person. Time period allotted to
complete the task is 72 hours.
These could simply just be db vales
table_task
.id
.user_assigned
.strart_date
.end_date
.status
.desc
If done, the other person will confirm so. If not, I want to take
certain actions (like blocking his account, sending an email, assign
the task to someone else etc.) What is the best way to do this?
This again, Admin panel of some form with a layout of assigned jobs, the ''worker'' should be required to post a job as ''done'', the ''admin'' can then confirm this. This can all be managed via Values in the db ''table_task.status''
As the count-down runs second-by-second, I guess I will have to run a
script every second.
^-- server suicide
Run the cron ever hour at most. If you have 1000 users. Then this cron will run 1000 a sec
in an hour this is, 60000*60
If you need to display the time use some jQuery of some form. There are lots of clock scripts.
Any of the users can trigger an event, as many times they wish. Each time this event is triggered, a row in a mysql table is created with the timestamp, their userid and other useful information. What I need to do is launch a script which runs exactly 12 hours after the event is triggered i.e. for each row in the table.
How can I achieve this in an automated and efficient fashion?
You could use a cron job which every minute launches the script.
In the script you should first fetch the row(s) and check if it's OK to run (if 12 hours passed) then continue, else stop.
I don't know if this will be very efficient, it depends on your number of entries in the database, but technically it's not expensive to just check if the current date matches a date fetched from the database + 12 hrs, I cannot say more because you didn't give too much details about your data.
You'd probably be better off with a cronjob
http://en.wikipedia.org/wiki/Cron
Potentially, you could look into MySQL event scheduler. Although It might not fit your needs, hard to really tell on the details given
http://dev.mysql.com/doc/refman/5.1/en/events.html
something like
CREATE EVENT myTimedEvent ON SCHEDULE EVERY INTERVAL 5 minutes DO CALL updateRows();
updateRows checks your criteria (12hours ago), if it is, perform whatever action you want to do. This requires your MySQL to be # version 5.1+ however
You would probably best have a cron job which runs every minute and checks for any rows in the database > 12 hours old that have not yet been processed the script and process them. This wont give you EXACTLY a 12 hour difference, but would give you a difference within a minute of that.
You would probably also want to make sure that script would be able to run within a few seconds such that you don't have overlap of the script running twice at the same time.
This could be done using CronJobs. If you have root access to your Server or a server administration toolkit that offers cronjob managment you would do it on your server. otherwise use an online cronjob service (google for cronjob online).
the cronjob then triggers a php script on your server in your defined interval, like every minute or every 5 minutes.
this script then selects all rows from your mysql table which are older then 12 hours (WHERE timestamp <= NOW() - INTERVAL 12 hour ) and performs your desired actions on each result and delete the result from the table (or mark it done),
just make sure that the fetching and the actions itself are faster than your cronjob interval, otherwise you would have two or more scripts working on the same rows.
The easy way for me is to make the page head contains
<head>
<meta http-equiv="refresh" content="43200"> <!-- 43200 for (12 hours × 60 mintes × 60 seconds) -->
</head>
This method is very helpful to avoid server time out, which you can't avoid if you are using only PHP code
Important if you start the script using submit button, it's recommended to make the form action="other_page" not the same page, and sure you should save your input values as cookie using setcookie function and grab it as a variable in the action page using $cookieVar = $_COOKIE['the_cookie_name'] ;
You may need to increase or decrease the $cookieVar value and update the value again using setcookie every time your head code http-equiv do the refresh automatically after the specific seconds (43200 in our example) depends on what you want to do
Note that if you make your action start automatically without pressing submit button you can do the action in the same page.
I did that idea before, I had 180,000 images in one folder and the server didn't allow me to download it all because it was showing me only first 7998 images, so I create a script to zip each 1000 image in a file outside the images folder and to avoid time out, I made the code refresh each 60 second , finally I got only 180 zip file :)
I run a procedure that takes about 20 minutes to complete, I just wonder if PHP can keep the connection active until the process finishes.
To be clear, this page will have a button which when you press it will call a php page to run a sql query, in the main page I just wait for the Http request to be complete to send a success message.
For queries that are set to take up some time, you should move some automation requests into the mix, preferably cronjobs if you have access to a linux server.
With cronjobs, you can create enteries in the database for specific values, linked to the user. The cronjob will kick in lets say, every 5 minutes to execute a query if a pending query has finished. This will minimize the fact the user will need to sit on the page until completion. Because you should know, the second the user navigates away from the active page; all active connections, queries etc will stop.
Once the script has complete, make a custom message at the end to send to the user letting them know that their process has been completed.
You should also know, PHP works down the script, from line 1 to the end; so if your hang is on line 40 for example; the script will sit on that line until the query has completed then carry on processing.
Edit: This is for example purposes only to point you in the direction that i'm getting at, and should not be used as you see it. This is merely a markup example
<?php
if (isset($_POST['ButtonToExecute']))
{
// Query to update a table in your database which an external PHP script will work with
// Example Table Structure:
/*
Username
State
*/
if ($state == 0)
{
// Then update state to 1 with username to the username for the query to take place on
}
else
{
// Warn user that their process will take longer to complete as their already is an active query in process
// but add them to a secondry pipeline which will be picked up on the next cronjob interval
}
}
?>
On your cronjob, might have:
<?php
if ($state=='1')
{
// Execute your script
// After query execution update state to 2
// if state == 2 then insert custom message/email to send
}
?>
Edit your crontab:
yourpreferrededitor /etc/crontab
^ Where yourpreferrededitor means your text editor, whether nano or other.
and your cronjob line:
* * * * * root /usr/bin/php /var/www/cron.php
^ This is taken from a current cronjob I have constantly running set for every minute of every day
A Cronjob will give the user the ability to navigate away from the page, because as I mentioned above, the second the user navigates away from the script.. All on going processes stop. The cronjob will carry on running throughout without no user interaction needed (apart from they make the initial request)
You could do it in an ordinary php script if you set the timeout limit and ignore user abort but this is a bad idea because your user will have no feedback if the script worked.
At the company I work at we had the same problem
What we did:
Run the query in a separate script.
Start the script WITHOUT waiting for results
Split the query into multiple parts (using limit and offset)
Have the query script write messages to a temp file
Implement a status screen fetching the current state from the log via ajax
BTW an example for all the wise guys asking why it takes so long:
using a transitive hull can speed up your application a lot if you have to deal with a tree with millions of nodes but building it can take hours.
You could try:
set_time_limit(0);
You may want to take a look at Set Time Limit
In your PHP ini you can set a max-execution time for scripts, however you NEVER want to have a user sit on a page loading screen for that long.
One thing that I could suggest would to e increase your max execution time to something around 30 minutes, and then call this in javascript after a page has already been rendered, so the user will not be left in the dark not knowing what the script is doing.