It is common for applications to have "heavy" and therefore "slow" processes that we want users to not be able to run several times in a short period of time or that these processes run one by one, so as not to overload the system. server, and thus continue giving a good response time to the rest of the processes and users.
Also, the same problem can arise when we want a resource in our system to be accessed only by a single process, waiting to be released for the rest of the processes that require that resource.
Some examples that may require this unique process management are:
- Reloading or copying information from another system (massive batch process).
- Data backup or backup of previous backups
- Preparation of heavy reports. System closure or reconfiguration processes.
- Use of a server resource (file, serial port, USB, digital certificate, etc.)
- Etc.
Objective
Have a logic, in the projects developed in PHPRunner , to control:
- That a specific process is only running once and the rest of the requests that occur are rejected by the system.
- That a specific process is only running once and that the rest of the concurrent requests are queued and released according to the order of arrival (FIFO queue).
DEMO: https://fhumanes.com/single_execution/
Technical Solution
Concurrency control can be performed at least with these 3 means.
- Through a “semaphore” of the operating system
- Through the blocking of a file.
- Through a database manager table.
In this example, control has been used by locking a file (files, to have several controls).
This is the image of the application:
2 buttons have been implemented:
(1) – Button to execute the process and reject the requests that concur in the execution.
(2) – Button to execute the process and queue the requests until the previous one is finished
The process is very simple, delay the process 15 seconds:
<?php
// time initial
$time_initial = date('h:i:s');
// sleep 15 seg
sleep(15);
// Time final
$time_final = date('h:i:s');
?>
The function that performs the control of a process and the rest, its rejection, is:
<?php
function single_execution( $semaphore, $process ) {
$path_semaphore = __DIR__."/semaphores/".$semaphore.".lock";
$fp = fopen($path_semaphore, "r+");
if ($fp == false ) { // file not found
return array(false ,"The semaphore file does not exist!");
}
if (!flock($fp, LOCK_EX|LOCK_NB, $blocked)) {
if ($blocked) {
// another process holds the lock
return array(false, "Couldn't get the lock! Other script in run!");
}
else {
// couldn't lock for another reason, e.g. no such file
return array(false , "Error! Nothing done.");
}
}
else {
// lock obtained
ftruncate($fp, 0); // truncate file
// execute Proccess
include ($process);
fflush($fp); // flush output before releasing the lock
flock($fp, LOCK_UN); // release the lock
return array(true, "Process executed correctly");
}
}
The function performed by the FIFO queue is:
<?php
function fifo_execution( $semaphore, $process ) {
$path_semaphore = __DIR__."/semaphores/".$semaphore.".lock";
$fp = fopen($path_semaphore, "r+");
if ($fp == false ) { // file not found
return array(false ,"The semaphore file does not exist!");
}
if (flock($fp, LOCK_EX)) { // acquire an exclusive lock
ftruncate($fp, 0); // truncate file
// execute Proccess
include ($process);
fflush($fp); // flush output before releasing the lock
flock($fp, LOCK_UN); // release the lock
}
fclose($fp);
return array(true, "Process executed correctly");
}
The programming of the 3-state buttons is:
Previous (Javascript)
$('a[id^="Process_unique"]').attr("disabled", true); // Deshabilitar botón
Server (PHP)
include ("MyCode/semaphore_code.php");
$status = single_execution("semaphore_1", DIR."/MyCode/slow_processes/process_1.php");
$result['status'] = $status[0];
$result['message'] = $status[1];
* After (JavaScript)
$('a[id^="Process_unique"]').removeAttr("disabled") // Habilitar botón
var message = 'Status = '+ result["status"]+' '+result["message"];
ajax.setMessage(message);
[If you are interested in this topic and want to obtain the code, ](https://fhumanes.com/blog/guias-desarrollo/guia-47-control-de-un-unico-proceso-en-ejecucion/)click here to access the article