2

I have a server function like this

function very_long_task($data) {}

This function is called using $.ajax() function clients-side.

The problem is that when my server-side function very_long_task() is executed the site is locked down. Meaning that if I tried to view another page of the website from a different tab or window, the website will not load until the very_long_task() function has completed.

Is there anyway to get around this either server-side or client-side?

UPDATED: 2015-11-3

The AJAX call is actually called many times because it is looping through all the elements in a list and performing an action on each of them. The very_long_task() function is then being called on each element.

For example, if there were a list of 20 elements then the very_long_task() function would be called 20 times. This does help a little bit in the overall responsiveness on that page but not on other pages.

UPDATED: 2015-11-3

Also this is built with WordPress so I can leverage some of their functions, but I have had no luck with wp_schedule_single_event since I need a return value.

https://codex.wordpress.org/Function_Reference/wp_schedule_single_event

UPDATED: 2015-11-3

Here is an updated view of my

function very_long_task($data) {

    session_write_close();

    // Very long task...

    return $data;

}
Kyle
  • 227
  • 2
  • 12
  • You could break apart the very long task into medium tasks and run them one at a time? Or cache it? Or run it via a CRON so that it's not locking up the site? – Mikel Bitson Nov 03 '15 at 20:42
  • Otherwise you could go for a [german](http://gearman.org) server process. – Jan Nov 03 '15 at 20:44
  • 1
    Sending the job to a message queue would probably be the best solution for this. You could write it yourself in php and use a scheduler to run it or use something like beanstalk or gearman. – jeroen Nov 03 '15 at 20:45
  • Thanks for the comments :) I have looked at Gearman and other schedulers but they don't seem to fit my needs since I need to return data back to the client-side function from my server-side PHP function. – Kyle Nov 03 '15 at 20:48
  • @Kyle You could save the data from Gearman to a database and poll it from your client side. – Jan Nov 03 '15 at 20:50
  • It seems that you need message queuing for the backend. So this is propably a duplicate of http://stackoverflow.com/questions/858883/run-php-task-asynchronously . In your fronted you just need to make sure that it's an asynchronous callback. – Sebastian G. Marinescu Nov 03 '15 at 20:52
  • @Sebastian G. Marinescu So you are suggesting that I run my `very_long_task ` function, which is being called via AJAX, through one of the options in the linked question you supplied? Would it be easier to calls this function server-side and not client side? Or does it not matter? – Kyle Nov 03 '15 at 20:59

2 Answers2

1

You'll want to call session_write_close() as soon as possible.

This is because while one page has called session_start(), the session file will be locked until the page finishes execution, or until the session is closed.

If this is not done, any page calling session_start() will wait for the lock to be lifted.

UPDATE

I think I know what's going on:

your browser limits the number of simultaneous connections to a server, typically somewhere between 2 and 10.

If you're making 20 asynchronous AJAX calls, and you open the Developer Console (F12 / control-shift-I), you'll probably find that not all of them are executing simultaneously. This would certainly leave no room for additional connections.

Note, that the session_write_close() is still necessary, otherwise the ajax calls will execute serially.

SUGGESTION

So, it is best to only make one AJAX call. If you want parallelism, you can fork child processes server-side.

You probably won't be able to use jQuery for this, because you'll want to send data from the server and flush()-ing it as it becomes available (HTTP streaming).

One solution I used in a WP importer plugin is not to use AJAX at all, but perform the long running operation, pushing out HTML and a <script> tag to update the UI.

Kenney
  • 9,003
  • 15
  • 21
  • Thanks for the quick response and I have already tried this with no luck. – Kyle Nov 03 '15 at 20:52
  • See my updated post. The thing is that the very_long_task function is being called multiple times on a page so the session_write_close() is therefore being called multiple times as well. Is this a problem? – Kyle Nov 03 '15 at 20:55
  • Are you calling `very_long_task` in the proper WP AJAX way? I.e., `defined(DOING_AJAX)` is true and such? And no, it's not a problem - every request to your website is a different process, so each of them has to close the session. Try to avoid re-starting the session once it's closed, as that introduces another lock.. – Kenney Nov 03 '15 at 20:57
  • Ok I removed the session start form the function call but it is still locking up the front-end of the website. I am calling this function from the back-end admin panel of WordPress and that page is responsive, meaning that I am able to click on links within the page that the AJAX tasks is being called from. The problem is that front-end pages are still being locked. Is there a way to solve this problem? – Kyle Nov 03 '15 at 21:02
  • There is, but we first need to know what is causing it. If you use a second browser (f.e. I use Firefox for dev and Chrome if I need a second session), does the site still stall? What exactly is the `very_long_task` doing? If it is updating the database, that would explain it. Since it is a front end issue, the problem is likely somewhere within a plugin or theme.. – Kenney Nov 03 '15 at 21:07
  • What happens if you change the real work being done by `very_long_task` with a `sleep()` of about equal duration (and return some dummy info)? – Kenney Nov 03 '15 at 21:09
  • Yes the `very_long_task` is querying the database. Also when I view the site from a different browser, the site is not being locked up :) So we are making progress. – Kyle Nov 03 '15 at 21:10
  • Possible to reduce the long query? do some proper indexing of the database? Is the query returning a lot of rows? If so how about using pagination? – Aaron Gong Nov 03 '15 at 21:15
  • @Aaron the `very_long_task()` is a calculation that queries the database and even makes post request to other servers to retrieve data on specific content. – Kyle Nov 03 '15 at 21:20
  • Could you check if the session is still inactive at the end of the long task (using [session_status](http://php.net/manual/en/function.session-status.php))? Maybe a plugin starts the session again (via a hook or something)? – Kenney Nov 03 '15 at 21:26
1

I'm not entirely sure what you mean by "locked down" but below are some things to try:

Make sure that your AJAX is asynchronous

$.ajax({
    url: '/start_very_long_task.php',
    async: true
});

Make sure your PHP accommodates the expected behavior

// start_very_long_task.php

function start_very_long_task()
{
    ini_set('ignore_user_abort','on');
    ini_set('max_execution_time', 0)
    session_write_close();

    do_very_long_task();
}

function do_very_long_task()
{
    // Very long task stuff
    // This can recursively call itself without making
    //   making multiple calls to session_write_close(), etc...
}

start_very_long_task();
MonkeyZeus
  • 20,375
  • 4
  • 36
  • 77
  • Thanks for the help but this function is being called within a WordPress site so the way that AJAX is handled is a bit different. https://codex.wordpress.org/AJAX_in_Plugins So it is not really possible for me to have a distinct file which handles the request. Instead I just have the function `very_long_task`, meaning that all logic has to be within that single function. – Kyle Nov 03 '15 at 21:06
  • @Kyle I see. I've never worked with WordPress but see my update for more inspiration. – MonkeyZeus Nov 03 '15 at 21:11
  • So as I stated above the ` session_write_close();` call seems to stop the lock up from the happening within different browsers but not the same browser. Would this mean that the only real person locked out of the site is the person running this very long task? – Kyle Nov 03 '15 at 21:14
  • @Kyle Different browsers will not lock up if you do or don't use `session_write_close();` because each browser gets it's own session ID; so session locking is not an issue when using different browsers. You are correct though; the only person that will be locked up is the person that fired off the AJAX request. – MonkeyZeus Nov 03 '15 at 21:17
  • Ok so my main concern is that as a site owner, if I start this `very_long_task` then will my viewers get locked out of the site? Or will the only person locked out be the site owner themselves? – Kyle Nov 03 '15 at 21:19
  • @Kyle Yes, site owner gets locked, all viewers are fine. If the site owner wants to view the site in the meantime then they can open a different web browser and surf freely. – MonkeyZeus Nov 03 '15 at 21:21