Let's say I have a PHP code that consumes from a message queue and run some class according to the message.
#/usr/bin/env php
//pseudo php code
while(true){
$message = $queue->getMessage();
$content = json_decode($message->content);
switch($content->type){
case 'a':
runFunctionA($content->data);
break;
case 'b':
runFunctionB($content->data);
break;
case 'c':
runFunctionC($content->data);
break;
}
$message->delete();
}
This is my first time using a message queue. Since I'm already on top of AWS, I'm going to try using AWS SQS. I think it will be much simpler since I don't have to deploy some queue server from scratch.
My first problem is how to ensure that the process will run again if for example in the runFunctionA there is an error causing the script to halt.
But after searching through StackOverflow, I found this thread 'Have a PHP script run forever, access a queue' and 'How can I keep an Amazon SQS PHP reciever script running forever?'. Basically I got the idea to create a cronjob to check a lock file. From my experience writing shell scripts, I can achieve this using start-stop-daemon like this. (1) Or is there a better or more common way?
But now I still can not figure out how to safely update the code, for example, when I want to update the content of runFunctionA. Currently I'm planning the queued tasks to be in the same codebase with the website because most of the business logic is already implemented there.
My current deployment mechanism is by storing the zipped code into the web-servers and change the link to new code. Something like below.
wget http://path/to/code.zip -O /path/to/temp/dir
rm /var/www
ln -s /path/to/temp/dir /var/www
#Let's say the forever loop is in script /var/www/queue_consume.php
Since the HTTP requests are short, I think deploying using this mechanism is pretty safe (and I think it's the most common way). But I'm not sure about updating long running PHP code.
My main question is (2) how to make the forever loop safely use the newly deployed runFunctionA code? Since I already have the idea using the start-stop-daemon above, I can basically restart the daemon. But again, (3) is there another more common way to do this. And lastly, (4) how to ensure the loop will at least finish running a task before the code being updated? My main concern is more about data consistency in the task. If the PHP script is restarted forcefully, there might be inconsistency in the database.
UPDATE
So far the only idea I have is to separate the loop and the tasks. In the loop I can do exec, for example,
#/usr/bin/env php
//pseudo php code
while(true){
$message = $queue->getMessage();
$return = 1;
$output = '';
exec("/var/www/tasks.php {$message}", $output, $return);
if ($return == 0)
$message->delete();
}
As for the consistency, I'm thinking to use PHP Process Control to catch signal sent by the deployer and delay the script restart until the current task is processing.