2

For some reason I can't find on google a solution for this. I have an option in a web app to upload a large amount of data (in a file) and through back-end processing (we use Java/Spring) to store this. It takes like 5 minutes. Does anybody know of a way that a user can launch this process and do other things and when it's done to inform the user?

A solution that I'm thinking about (not sure if there are better once, that's why I'm here) is to make an AJAX call (we happen to use the jQuery library) which will pass the file to a controller, then while the controller will be processing the file it will periodically send something small to the stream so that timeout doesn't happen and then once it's finished it will inform about that the web app upon which it will inform the user.

SBel
  • 3,315
  • 6
  • 29
  • 47
  • Do you care about *how* the end user is notified? How about a simple AJAX polling mechanism? – Will Aug 01 '13 at 21:09
  • @Will I do care how the user is notified, it should be user-friendly. What are you getting at? – SBel Aug 01 '13 at 21:11
  • Ok, are you more concerned about how to compute the progress on the server side, or how to present it to the user? For the client side, I think AJAX polling would probably suffice; you just need a server endpoint that can report progress. As for building the server logic to track the progress: http://stackoverflow.com/questions/254719/file-upload-with-java-with-progress-bar – Will Aug 01 '13 at 21:17
  • xhr2 supports progress callbacks. http://www.html5rocks.com/en/tutorials/file/xhr2/ – Bart Aug 01 '13 at 21:31
  • @Bart I need a solution that will work on all the browsers so I would only use a jQuery plugin. – SBel Aug 01 '13 at 21:42

4 Answers4

1

I had to solve a problem like this recently and it was really easy. He's why I say so.

  1. With HTTP 1.1 protocol, the server connection is kept open until the last resource for a request is returned. Any HTTP 1.1 compliant web-server will do this for you under the hood without any effort on your part. This alone makes your problem much, much easier to solve

  2. With servlet 3.0, you should take advantage of the new asynchronous feature (although you can roll out something similar on your own in servlet < 3.0). The server allocates a new thread for each incoming request from it's thread pool. Then using your own custom thread-pool, hand off the processing of this request thread to a custom-thread together with the asyncContext. Your own thread will handle this long-running process, and the server's thread returns immediately to process other requests. The asyncContext contains the original request/response objects, but they're in a 'frozen' state. When your long-running process completes, it will invoke the asyncContext.complete() method. This action will commit the original request/response that was in 'frozen' state.

  3. To the client, this asynchronous process looks like the server is taking forever to respond, and the client will therefore sit patiently waiting for a response. You will need to do nothing out of ordinary on your part.

  4. On the client side, any method of invoking an ajax request is sufficient. No polling is required. The client will happily sit and wait for a response. The 'readyState' attribute of the xmlHttpRequest object will take care of this for you. Once the response is committed by the server, the 'readyState' value will change to 4 and from there you can update your UI.

On the server side, you should probably wrap the class having the method to the long-running process inside an inner class which will then invoke the long-running process and also hold a boolean attribute such 'running = true/false'. That way if in the middle of you long-running request, someone tries to invoke the same process again, they will be able to know if it's running already. Now that's more details than you asked for.

Anyway, I hope I helped and at the same time gave you clues as to how to move forward.

mainas
  • 754
  • 1
  • 6
  • 15
0

Can we use jquery ajax for this

success: function(xhr_data) {
  console.log(xhr_data);
  if (xhr_data.status == 'pending') {

    if (cnt < 6) {
        cnt++;
        setTimeout(function() { ajax_request(); }, 15000); // wait 15 seconds than call ajax request again
    }

  } else {
    success(xhr_data);
  }
}
sreeprasad
  • 3,242
  • 3
  • 27
  • 33
  • Your answer sounds like a question :) – Bart Aug 01 '13 at 21:32
  • :) true but I was not sure if @SBel worries about lot of network connections or if this would be an optimum solution for him. Depends on type of application he is working on. – sreeprasad Aug 01 '13 at 21:36
  • @SREEPRASADGOVINDANKUTTY I don't understand your proposition entirely. I'm starting to think that maybe the back end should write its progress to a database table and the front end should check periodically this table and report to the user. How does this sound? – SBel Aug 01 '13 at 21:40
  • Instead of front end checking the database, which may cause db network connections, check a "status" flag. Initially status flag is "pending" Once the db is completed its work, then update status flag to "complete" and this informs the user about the update. – sreeprasad Aug 01 '13 at 21:49
  • @SREEPRASADGOVINDANKUTTY I don't understand where this "status flag" will be? – SBel Aug 01 '13 at 21:52
  • "status" flag would be in field in service layer . Once dao completes the status flag in the service layer would be updated. – sreeprasad Aug 01 '13 at 22:09
0

I would consider a push notification SaaS like http://pusher.com/

Client sends request to server that takes a while:

POST /process-file

Server responds

HTTP 202 Accepted

{ channelName:'some-channel', events:[{name:'my-processing-complete-event'}] }

On the client, in JavaScript, subscribe to channel and listen:

var channel = pusher.subscribe('some-channel');
channel.bind('my-processing-complete-event', function(message){
  alert(message);
});

On the server, when the processing is complete, you notify your push service, which then notifies all clients.

pusher.trigger("some-channel", "my-processing-complete-event", "processing done");
Neil McGuigan
  • 46,580
  • 12
  • 123
  • 152
0

I think that the best solution is as follows. Have a DB table that monitors back end tasks. Periodically the front end queries this table through a back end service for the status. Once the status is complete then it informs the user.

SBel
  • 3,315
  • 6
  • 29
  • 47