tags:

views:

90

answers:

3

Hi,

I have a php script that needs to run once every 5 minutes. Currently I'm using a cron job to run it (and it works great) but my host only allows a minimum time of 15 minutes.

So my question is, can I use visitors to trigger the running of a php script every 5 minutes. I can easily just record the last time it ran, and re-run it based on elapsed time.

However, I'm worried about race conditions. It is important that the script only gets run once every 5 minutes.

My script takes about 60 seconds to run. It writes to a couple files during this time. If the script ran more than once it would corrupt files. Also, if I get no vistors for 10 minutes, then running once when the next vistor arrives is fine.

Is there some standard way to accomplish this task?

Thanks!

+3  A: 

Have you considered just having your script run an infinite loop with a sleep to wait 5 minutes between iterations?

for (;;)
{
  perform_actions();
  sleep(300);
}

Alternatively, you could have a file (for example, is_running), and get an exclusive lock on it at the start of your script which is released at the end. At least this way you will not do anything destructive.

You could also combine these two solutions.

$fp = fopen("is_running", "r+");

/* is it already running? */
if (! flock($fp, LOCK_EX | LOCK_NB)) return;

for (;;)
{
  perform_actions();
  sleep(300);
}

And then have the cron job still run every 15 minutes. If the process is still running, it will just bail out, otherwise it will relaunch and resume updating every 5 minutes.

Brandon Horsley
This seems like a good idea and a pretty good work around. I'm guessing I need to call php's set_time_limit. And then I'm hopeing my host won't automatically kill long running processes... Still, this seems like my best bet. Thanks.
Imbue
`set_time_limit` is the function you need to adjust the timeout. http://php.net/manual/en/function.set-time-limit.php I would set it to something like 330 every time the script is run so that you don't have to worry.
Icode4food
Just to let you guys know, the host allowed my script to run for approx. 26 hours before killing it. Shortly there after, cron popped on another that noticed the file was unlocked and I was back in business. One thing that does scare me is what would happen if the host kills my script while it is writing data. In that case, data could be corrupted until cron has a chance to run another script. In other words, a few times a year I would probably be serving corrupted data for about 5-10 minutes.
Imbue
@Imbue, maybe you should not make it an infinite loop, and instead have it execute once, sleep(300), execute again and end. This way it runs 2 times in 10 minutes, and cron launches it 5 minutes later, effectively running once every 5 minutes. The crashing while writing data, if you are using flat files, could be handled by operating to temporary files, and then renaming them into place once all of the work is done. If it is a database, there are other protective measures to prevent corruption.
Brandon Horsley
+1  A: 

If you cannot do what @Brandon suggested, I would recommend the approaching this in the same way I did when writing a daemon in PHP (not the best solution but I was practically forced to do this).

In my case as well the script accessed a (log)file and did processing on it, afterwards inserting the results in the database. So to ensure that I don't have two files running at the same time, I created a "status" file on which the script acquired a lock and if not able to do so if failed gracefully.

$fh = fopen('status_file', 'w');

/**
 * LOCK_NB is required because otherwise your script would stall until
 * a lock is aquired, queing a bunch of scripts.
 */
if(!flock($fh, LOCK_EX | LOCK_NB)) {
  exit 1; // our job is done here
}
mhitza
+3  A: 

Lame answer for a lame situation (the ISP, not the poster). Schedule 12 cron jobs, all calling the same script, each running once per hour, but calling at a different 5 minute mark.

00 * * * * root echo "run at :00 of every hour"
05 * * * * root echo "run at :05 of every hour"
10 * * * * root echo "run at :10 of every hour"

etc until :55. But I stand by my original comment - find a new ISP :)

Erik
I'm sure this would work, and it's probably a decent solution, but I'm afraid of what would happen if my host noticed it.
Imbue
@Imbue - So you think your host would look more kindly upon an infinite loop?
Peter Ajtai
I think an infinite loop that spends almost all of its time in sleep would be less noticeable, and maybe a bit less defiant. Or not. It's hard to say really.
Imbue
I really doubt the PHP set up on host gator will allow a script to run indefinitely. And the more I think about it, my solution will probably fail too. You could use a web-based cron - there's one that costs $10/year and it will call your script via http, but I forget the name. :)
Erik
Well, I'm testing it right now. I can see the process running in CPanel, it's using 0% CPU (while sleeping). I'm just logging a time each iteration. The script only needs to run for 10 minutes actually. If cron is set for 15 minutes, the script goes Start -> Work -> Wait 5 min -> Work -> Wait 5 min -> Work -> Quit. Then cron kicks in 5 minutes later.
Imbue
@Imbue, nice, let me know if it works, it's always rewarding to see "in theory" become "in practice".
Brandon Horsley
It's working fine right now. The only question is whether the host will allow it. I don't think I'm going to sleep too soundly tonight. lol.
Imbue