How to use semaphone with PHP
Semaphore is a protected variable that can be used to control access to a resource. I’ve used a semaphore to prevent a PHP script from running simultaneously. For example I have a PHP script that runs every Tuesday to process a weekly newsletter. This script first selects a list of recipients to send. The script then sends each recipient a copy of the newsletter. The list is more than 10,000 subscribers and each subscriber is processed individually in order to customize the newsletter content. As each subscriber is processed the script updates the database for that subscriber with a last sent date of today. If the script runs a second time the subscribers will not be selected since they were updated with a last sent date of today. However if the script is run a second time before the first instance completes the initial list is repopulated and the newsletter is sent twice. To prevent the script from running simultaneously I use a semaphore to “lock” the process.
Semaphore usage is pretty straight forward. There are 4 functions:
- sem_acquire() – Attempt to acquire control of a semaphore.
- sem_get() – Creates (or gets if already present) a semaphore.
- sem_release() – Releases the a semaphore if it is already acquired.
- sem_remove() – Removes (deletes) a semaphore.
The following pared down script shows a basic example usage of a semaphore to lock the script and prevent it from running simultaneously.
<?php // exclusive control $semaphore_key = 2112; // unique integer key for this semaphore (Rush fan!) $semaphore_max = 1; // The number of processes that can acquire this semaphore $semaphore_permissions = 0666; // Unix style permissions for this semaphore $semaphore_autorelease = 1; // Auto release the semaphore if the request shuts down // open a new or get an existing semaphore $semaphore = sem_get($semaphore_key, $semaphore_max, $semaphore_permissions, $semaphore_autorelease); if(!$semaphore) { echo "Failed to get semaphore - sem_get().\n"; exit(); } // acquire exclusive control - wait for semaphore availability if (sem_acquire($semaphore, false)) { // get the MySQL result set of recipients ($result) - omitted for readability // bail if no one to process - double run if (count($result) == 0) { echo "Zero members to process - cancelling"; // release exclusive control sem_release($semaphore); exit(); } // process members if (count($result) > 0) { foreach ($result as $row) { // send the newsletter - omitted for readability } } // release exclusive control sem_release($semaphore); } // semaphore acquired ?>
References
PHP Semaphore
PHP if
PHP echo
PHP count
PHP foreach
PHP exit
This does not work! You’re checking if the resource to the semaphore is set, which is always true, even though the process is already running. You need to check if you can actually get the resource…
so: if( !sem_aquire( $semaphore, true )) exit( “we’re already running” );
if you set the ‘true’ to ‘false’ the process will wait until the semaphore is released by the running process before it continues, if set to true is will return false immediately if the semaphore is already aquired
Patrick, you are correct and thank you for your feedback. I have updated the code snippet to reflect testing the semaphore acquisition.
Attention all planets of the Solar Federation
Attention all planets of the Solar Federation
Attention all planets of the Solar Federation
We have assumed control
We have assumed control
We have assumed control
Monte for the win!