Long polling in spring mvc(async) - java

My operation takes 30 mins to process which is invoked by a rest call request. i want to give the client an immediate response telling operation in progress,and processing should happen in another thread, what is the best way to crack this out,Is deferred result the only way.

30 minutes is a long time. I'd suggest you using websockets to push progress updates and operation status.

Since you are providing rest services, another approach could be to immediately return 'Accepted' (202) or 'Created' (201) to the client and provide a link to another service that would provide updates about the progress status of the processing. This way the client is free to decide whether to poll the server for updates, or just provide the user an 'update status' button.

Use a message queue (ActiveMQ, Redis).
Send request from client.
Controller gets request, post process/message in message queue.
Send response back to client saying it's processing.
Another thread to look for changes/new process in message queue.
Execute the process - Update the status in message queue each step is completed. - (started/running/completed/failed).
You can show the status of process everytime with the id of process in queue.

Related

Stay subscribed to Flux/Mono after client disconnect in Spring WebFlux

I have a service where a couple requests can be long running actions. Occasionally we have timeouts for these requests, and that causes bad state because steps of the flux stop executing after the cancel is called when the client disconnects. Ideally we want this action to continue processing to completion.
I've seen WebFlux - ignore 'cancel' signal recommend using the cache method... Are there any better solutions and/or drawbacks to using cache to achieve this?
there are some solutions for that.
One could be to make it asyncron. when you get the request from the customer you can put it in a processor
Sinks.Many<QueueTask<T>> queue = Sinks.many().multicast().onBackpressureBuffer()
and when the client comes from the customer you just push it to the queue and the queue will be in background processing the items.
But in this case customer will not get any response with the progress of item. only if you send it by socket or he do another request after some times.
Another one is to use Chunked http request.
#GetMapping(value = "/sms-stream/{s}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<String> streamResponse(#PathVariable("s") String s) {
return service.streamResponse(s);
}
In this case the connection will be open and you can close it automatically in server when processing is done

Cancel REST service when request is cancelled

I have a snippet from angular UI that will call myService.getNames() when user types in a letter in the field. The switchMap will cancel the previous request whenever the user types in another letter in the field.
.pipe(
debounceTime(500),
switchMap(value => this.myService.getNames(value))
)
This service will call the REST endpoint http://localhost:8080/listing?value=<value_sent_from_client>. The query for retrieving the list of names takes some time to complete. If the user edited the field 3 times, there will be 2 cancelled requests and 1 on-going request.
On the server side, how do you cancel the 2 previously running queries? Or will they get cancelled automatically?
You cannot cancel request on server side. The solution might be in more sophisticated algorithm, like:
each request are putting into queue and return immediately not waiting for processing to be finished (storing in DB, etc.)
queue replace previous items if new items are present from same user
client subscribes to updates from server via web-sockets
Or any other approach.

How to get the response if returned after the time out occurs

I am consuming a REST web service from Java code using Apache commons HTTP client API. If no response returns within the socket timeout value configured in the connection manager parameters, socket time out exception occurs. In such cases as the thread returns the exception to the caller class, even if the REST service returns response few secs later, will be lost.
Is it possible to create a new thread which will still listen to the service even after the timeout and just logs the response, while the main thread returns the exception to the caller class?
Is there any better way to achieve this?
Thanks.
The pattern you are most likely looking for involves asynchronous requests. For every action you post you create a unique "job" id and with that a specific URL for the job status. After starting the job, you can then query on that specific job instance's status. For example:
POST to /actions
Returns 202 Accepted & include a Location header to /actions/results/1234
Immediately GET /actions/results/1234 to ascertain it's status.
If it returns a 2xx your job is done.
If it returns 404, wait 10 seconds (or whatever) and try again.
Once you are happy with the result, issue a DELETE to /actions/results/1234 to clean up after yourself.
Of course you don't have to return 404 if the job is not done, there are other strategies for checking on the status - the key thing is that it's a subsequent call.

Stop Ajax request as well as the process started on controller in Spring

I am using the Spring MVC and I have created Controllers and I am accessing them using the JQuery Ajax request, but sometimes it may be possible that the process takes long time, so I want to give the user option to stop the request for that I am using the abort function of JQuery and it stops the Ajax request successfully but it does not stop the process started on the controller. Is there any other way to do that?
If the request has already been sent to the server then the server will process the request even if we abort the request but the client will not wait for/handle the response.
Maybe you'll have to write some custom logic where initiate a thread in controller for each such ajax call and track their thread id. Then on abort request go back in controller and kill that thread.
Just a basic idea, I haven't implemented it myself so not sure about code/logic problems you might face.
Your jQuery's abort() will stop the client to listen for the response but still the server will process.
I can think of something:(I hope the process is long enough for you to stop by the way)
Continuous Polling using a thread. Have a status flag that reads at high frequency so that when you do an abort, you update the status of the request to stop. If continuous polling is enabled, you can check that status is now to abort and the thread is stopped or something like that.
If you don't use any custom logic there is no way to stop an ongoing process at controller level. Because controller process and UI process are two different layers the only connection between them is socket request - response connection.
abort on javascript side could cause big risk for your application, backend will complete process but ui won't be aware of it. You can manage your response time on controller side and return an error and abort your controller process with your own logic. for example if you have some loop on Controller put a timecheck, or you have another socket connection like db configure your connection based on timeout parameter.
What you want to do is directly related to your controller implementation.
Declare a variable to store the ajax request
var req = $.ajax({
type: 'GET',
url: '<*url*>',
......
});
We can use my request .abort()
req.abort();
Check for reference jQuery ajax

Architecture advice about managing UDP calls

I would like to have an advice for this issue:
I am using Jbos 5.1.0, EJB3.0
I have system, which sending requests via UDP'S to remote modems, and suppose to wait for an answer from the target modem.
the remote modems support only UDP calls, therefor I o design asynchronous mechanism. (also coz I want to request X modems parallel)
this is what I try to do:
all calls are retrieved from Data Base, then each call will be added as a message to JMS QUE.
let's say i will set X MDB'S on that que, so I can work asynchronous. now each MDB will send UDP request to the IP-address(remote modem) which will be parsed from the que message.
so basicly each MDB, which takes a message is sending a udp request to the remote modem and [b]waiting [/b]for an answer from that modem.
[u]now here is the BUG:[/u]
could happen a scenario where MDB will get an answer, but not from the right modem( which it requested in first place).
that bad scenario cause two wrong things:
a. the sender which sent the message will wait forever since the message never returned to him(it got accepted by another MDB).
b. the MDB which received the message is not the right one, and probablly if it was on a "listener" mode, then it supposed to wait for an answer from diffrent sender.(else it wouldnt get any messages)
so ofcourse I can handle everything with a RETRY mechanisem. so both mdb's(the one who got message from the wrong sender, and the one who never got the answer) will try again, to do thire operation with a hope that next time it will success.
This is the mechanism, mybe you could tell me if there is any design pattren, or any other effective solution for this problem?
Thanks,
ray.
It's tough to define an exacting solution without knowing the details, but I will assume that when a response is received from a modem (either the correct one or not), it is possible to determine which exact modem the request came from.
If this is the case, I would separate out the request handler from the response handler:
RequestMDB receives a message from the [existing] queue, dispatches the request and returns.
A new component (call it the ResponseHandler) handles all incoming responses from the modems. The response sender is identified (a modem ID ?) and packages the response into a JMS message which is sent to a JMS Response Queue.
A new MDB (ResponseMDB) listens on the JMS Response Queue and processes the response for which the modem ID is now known.
In short, by separating concerns, you remove the need for the response processing MDB to only be able to process responses from a specific modem and can now process any response that is queued by the ResponseHandler.
The ResponseHandler (listening for responses from the modems) would need to be a multithreaded service. You could implement this as a JBoss ServiceMBean with some sort of ThreadPool support. It will need a reference to the JMS QueueConnectionFactory and the JMS response queue.
In order to handle request timeouts, I propose you create a scheduled task, one for each modem, named after the modem ID. When a request is sent, the task is scheduled for execution after a delay of the timeout period. When a response is received by the ResponseHandler, the ResponseHandler queues the response and then cancels the named task. If the timeout period elapsed without a cancellation, the scheduled task executes and queues another request (an reschedules the timeout task).
Easier said than done, I suppose, but I hope this helps.
//Nicholas

Categories

Resources