I'm working on an online PHP application that has a need for delayed PHP event. Basically I need to be able to execute arbitrary PHP code x many seconds (but it could be days) after the initial hit to a URL. I need fairly precise execution of these PHP event, also I want it to be fairly scalable. I'm trying to avoid the need to schedule a cron job to run every second. I was looking into Gearman, but it doesn't seem to provide any ability to schedule events and as I understand, PHP isn't really meant to run as a daemon.
It would be ideal if I could tell some external process to poll a "event checker" url on PHP server at the exact time that the next event should be run. This poll time will need to be able to decreased or increased at will since event can be removed and added to the queue and. Any ideas on an elegant way to accomplish this? There is simply to much overhead in calling PHP externally (having to parse HTTP request or calling via CLI) to make this idea feasible for my needs.
My current plan is write a PHP daemon that will run the event and interface with it from the PHP server with gearman. The PHP daemon would be build around SplMinHeap so hopefully the performance wouldn't be to bad. This idea leaves a bad taste in my mouth and I was wondering if anyone had a better idea? Ideas changed slightly. Read Edit 2.
EDIT:
I'm creating an online game that evolves players taking turns with variable time limit. I'm using XMPP and BOSH to allow me to push messages to and from my clients, but I've got that part all done and working. Now I'm trying to add an arbitrary event that triggers after play from the client to let the client (and other ppl in the game) that he took to long. I can't use timed trigger on the client side because that would be exploitable (since the client can play by themselves). Hope that helps.
EDIT 2:
Thank you all for your feedback. While I think most of your ideas would work well on small scale, I have a feeling they wouldn't scale very well (external event manager) or lack the exactness this project requires (CRON). Also, in both of those cases they are external pieces which could fail and add complexity to an already complex system.
I personally feel that the only clean solution that meets the requirements for this project is to write a PHP daemon that handles the delayed events. I've begun writing what I think is the first PHP runloop. It handles watching the sockets and executing delayed PHP events. Hopefully when I'm closer to being done with this project I can post up the source, if any of you are interested in it. So far in testing it has shown to be promising solution (no problems with memory leaking or instability).
EDIT 3: Here is a link to the PHP event loop library called LooPHP for those who are interested.
TL;DR Requirements
- Call (preferably natively) PHP at a delayed time (ranging from seconds to days)
- Handle creation/updating/deletion of events arbitrarily (I'm expecting a high amount of canceled call).
- Handle high load of events scheduled (100-1000 a second per server)
- Calls should be within one second of it's scheduled time
- At this point i'm not open to rewriting the code base into another language (maybe some day I will)
Here's the correct answer, but you may not like it.
PHP is designed entirely around being used as a request-response (http) language, and thus doesn't support what you are looking for - it's great to hack and find ways around, but it will be just that, a hack, whatever 'solution' you end up getting.
What you really need is an event driven language that supports xmpp, and for that you need look no further than node.js /v8 and the supporting XMPP libraries - this natively supports and is designed for just what you need. you could also go down the Java route, but if you want to port quickly and get a whole host of new features and support for what you are doing, node is the one.
If you insist on going with PHP (as I have many times over many years) the 'lightest' and most effective way to do this is a persistent PHP deamon with an event Queue in a database - sadly!
A can't think of anything that does everything you asked for:
The trivial way would be to use a combination of the following functions:
However, like @deceze said it's probably not a very good idea since if you set up a high delay Apache could eventually kill the child process (unless you're using PHP CLI, that would make it easier). It also doesn't allow you to change / delete the event unless you set up a more complex logic and a database to hold the events. Also,
register_shutdown_function()
might be useful if you want to go this road.A better approach would be to set up a CRON job in my opinion.
checkout this with redis . may be useful to your problem
https://github.com/chrisboulton/php-resque-scheduler
I think a PHP only solution will be hard(almost impossible) to implement. I came up with two solutions to your problem.
PHP/Redis solution
Question asked by Kendall:
Redis is very stable. The developer really writes some clean C code. You should check it out on github ;). Also a lot of big sites are using redis. For example github.They had a really interesting blog post how they made github fast :). Also superfeedr uses redis. There are a lot more big companies which are using redis ;). I would advise you to google for it ;).
PHP is very PHP friendly. A lot of users are writing PHP libraries for redis. The protocol is really simple. You can debug it with telnet ;). Looking quickly predis for example has the blocking pop implemented.
I think you should use something like ZRemCommand.
What I came up with(Pseudo-code....):
processor.php:
client.php:
wakeup.php:
Something along the lines of this you could also write a pretty efficient scheduler using PHP(Okay redis is C so kickass fast :)) only and it would be pretty efficient as well :). I would also like to code this solution so stayed tuned ;). I think I could write a usable prototype in a day....
My java solution
This morning I think I created a java program which you can use for your problem.
download:
Visit github's download page to download the jar file(with all dependencies included).
install:
java -jar schedule-broadcaster-1.0-SNAPSHOT-jar-with-dependencies-1277709762.jar
Run simple PHP snippets
php -f scheduler.php
php -f receiver.php
Questions
I created these little snippets so that hopefully you will understand how to use my program. There is also a little bit documentation in the WIKI.
App Engine's TaskQueue
A quick solution would be to Use Google's app engine task queue which has a reasonable free quota. After that you have to pay for what you use.
I would just use cron to run a PHP file every so often (i.e. 5 minutes). The PHP file would check if there are any events that need to be fired within the next interval, grab the list of interval events, and sleep until the next event. Wake up, fire next event(s) in the list, sleep until the next one, repeat until done.
You could even scale it by forking or launching another php file to actually fire the event. Then you could fire more than one event at the same time.
What about using either cron to run a checker, that can the execute stuff from the DB for example.
Or using the "at" linux command to schedule execution of some command?