Id like very much to have second thoughts on this approach Im implementing to handle very long processes in a web application.
The problem
I have a web application, all written in javascript, which communicates with the server via an API. This application has got some "bulk actions" that take a lot of time to execute. I want to execute them in a safe way, making sure the server won't time out, and with a rich feedback to the user, so he/she knows what is going on.
The usual approach
As I can see in my research, the recommended method of doing that is firing a background process in the server and make it write somewhere how its going so you can make requests to check on it and give feedback to the user. Since Im using php in the back-end, the approach would be more or less what is described here: http://humblecontributions.blogspot.com.br/2012/12/how-to-run-php-process-in-background.html
Adding a few requisites
Since Im developing an open source project (a WordPress plugin) I want it to work in a variety of situations and environments. I did not want to add server side requirements and, as far as I know, the background process approach may not work in several shared hosting solutions.
I want it to work out of the box, in (almost) any server with typical WordPress support, even if it ended up beeing a bit slower solution.
My approach
The idea is to break this process in a way it will run incrementally through many small requests.
So the first time the browser sends a request to run the process, it will run only a small step of it, and return useful information to give the user some feedback. Then the browser does another request, and repeats it until the server informs that the process is done.
In order to do this, I would store this object in a Session, so the first request will give me an id, and the following requests will send this id to the server so it will manipulate the same object.
Here is an conceptual example:
class LongProcess {
function __construct() {
$this->id = uniqid();
$_SESSION[$this->id] = $this;
$this->step = 1;
$this->total = 100;
}
function run() {
// do stuff based on the step you are in
$this->step = $this->step + 10;
if ($this->step >= $this->total)
return -1;
return $this->step;
}
}
function ajax_callback() {
session_start();
if (!isset($_POST['id']) || empty($_POST['id'])) {
$object = new LongProcess();
} else {
$object = $_SESSION[$_POST['id']];
}
$step = $object->run();
echo json_encode([
'id' => $object->id,
'step' => $return,
'total' => $object->total
]);
}
With this I can have my client to send requests recursivelly and update the feedback to the user as the responses are recieved.
function recursively_ajax(session_id)
{
$.ajax({
type:"POST",
async:false, // set async false to wait for previous response
url: "xxx-ajax.php",
dataType:"json",
data:{
action: 'bulk_edit',
id: session_id
},
success: function(data)
{
updateFeedback(data);
if(data.step != -1){
recursively_ajax(data.id);
} else {
updateFeedback('finish');
}
}
});
}
$('#button').click(function() {
recursively_ajax();
});
Of course this is just a proof of concept, Im not even using jQuery in the actual code. This is just to express the idea.
Note that this object which is stored in the session should be a very lightweight object. Any actual data beeing processed should be stored in the database or filesystem and only reference it in the object so it knows where to look for stuff.
One typical case would be processing a large CSV file. The file would be stored in the filesystem, and the object would store a pointer to the last processed line so it knows where to start in the next request.
The object may also return a more verbose log, describing everything that was done and reporting errors, so the user have complete knowledge of what has been done.
The interface I think would be great is a progress bar with a "see details" button that would open a textarea with this detailed log.
Does it make sense?
So now I ask. How does it looks like? Is it a viable approach?
Aucun commentaire:
Enregistrer un commentaire