I'm using #Suspended AsyncResponse response in my requests and starting threads to process the request. When the process finishes, I'm trying to resume the response but RestEasy is marking the request as done because the request thread has finished and no timeout was set in the response. If I set timeout, it works fine but I would need to set the timeout in every asynchronous request I want want to implement. Is there anyway to horizontally set the timeout to all my suspended AsyncRequests?
Unfortunately, the JAX-RS 2.0 specification, the RESTEasy documentation and the Jersey documentation don't mention anything about setting a default timeout for the AsyncResponse.
The Jersey documentation mentions the following:
By default, there is no timeout defined on the suspended AsyncResponse instance. A custom timeout and timeout event handler may be defined using setTimeoutHandler(TimeoutHandler) and setTimeout(long, TimeUnit) methods. The setTimeoutHandler(TimeoutHandler) method defines the handler that will be invoked when timeout is reached. The handler resumes the response with the response code 503 (from Response.Status.SERVICE_UNAVAILABLE). A timeout interval can be also defined without specifying a custom timeout handler (using just the setTimeout(long, TimeUnit) method).
So, the solution won't be different from the solution you are already using:
#GET
public void longRunningOperation(#Suspended final AsyncResponse asyncResponse) {
// Register a timeout handler
asyncResponse.setTimeoutHandler(new TimeoutHandler() {
#Override
public void handleTimeout(AsyncResponse asyncResponse) {
asyncResponse.resume(Response.status(SERVICE_UNAVAILABLE)
.entity("Operation timed out. Please try again.").build());
}
});
// Set timeout
asyncResponse.setTimeout(15, SECONDS);
// Execute long running operation in new thread
executor.execute(new Runnable() {
#Override
public void run() {
executeLongRunningOp();
asyncResponse.resume("Hello async world!");
}
});
}
Related
We are using spring-kafka-2.2.8.RELEASE. I have an specific situation where I need help. I have 4 topics topic, retryTopic, successTopic and errorTopic. If topic fails, should be redirected to retryTopic where the 3 attempts to retry will be made. If those attempts fails, must redirect to errorTopic. In case of sucess on both topic and retryTopic, should be redirected to the sucessTopic. This situation is already implemented based on the question How to retry with spring kafka version 2..2.
But now, I have a new situation where I need to call the retryTopic listener from inside the topic listener based on a business logic error without an Exception been thrown(it already calls the retryTopic when an exception is thrown and it must remain with this behavior). And I also need to know on which retry attempt number the retryTopic is been called as a paramater of the listener bellow.
#KafkaListener(id = "so60172304.2", topics = "retryTopic")
public void listen2(String in) {
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.execute(new RetryCallback<Void, RuntimeException>() {
#Override
public Void doWithRetry(RetryContext retryContext) throws RuntimeException {
// Can I get the retry count here? It didn't work
Integer count =RetrySynchronizationManager.getContext().getRetryCount());
return this.doWithRetry(retryContext);
}
});
}
There is no reason you can't call one listener from another (but you won't get retries unless you call it using a RetryTemplate in the first method).
If you use a RetryTemplate configured on the container factory to do the retries (rather than adding a BackOff to the SeektoCurrentErrorHandler in versions 2.3.x and higher), you can obtain the retry count (starting at zero) like this...
#KafkaListener(id = "so60172304.2", topics = "retryTopic")
public void listen2(String in) {
int retryCount = RetrySynchronizationManager.getContext().getRetryCount();
...
}
getContext() will return null if you call this directly from the first method (unless you wrap the call in a RetryTemplate.execute()).
In 2.5.x a delivery attempt header will be available (optionally) even if using the SeektoCurrentErrorHandler with a BackOff instead of using a RetryTemplate in the container factory.
Our ASP.NET Web API 2 application is consumed by mobile applications. Using Azure Application Insights we detected many responses with response code 500(Internal server error) without any Exception associated with them in Application Insights. During debugging session we did not encounter any Exception thrown.
We had a suspicion that this could be caused by client disconnects. After implementing a .net application simulating disconnects, we could replicate this issue even on a clean webapi2 project.
After further investigation we found out, that the result code 500(after the client is disconnected) occurs only when specific conditions are met. The request need to be cancelled on a non GET http operation and before ExecuteRequestHandler asp.net event is reached. On GET requests we cannot replicate this issue, neither on requests which entered or passed the ExecuteRequestHandler event.
Our goal is to filter out client disconnects from logs and focus on real issues.
This issue may be related to ASP.NET Web API OperationCanceledException when browser cancels the request, however the accepted solution does not work, because the disconnect occurs before any DelegatingHandler is reached. We would not use the mentioned solution, because client disconnects is not a Server issue but rather a client. For example in netcore the cancelled requests have response code 0 in logs. Anyway, the client will not see the result nor the result code because it is already gone.
Other possibly related question.
We are using the latest version Microsoft.AspNet.WebApi v5.2.7 and the investigation take place only on a development machine with IISExpress.
UPDATE
Including the minimal code to reproduce on clean webapi2 project.
Global.asax.cs
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
protected void Application_EndRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
Debug.WriteLine($"{context.Response.StatusCode}:{context.Response.SubStatusCode}:{context.Request.Path}:{context.Request.Url.AbsoluteUri}");
}
}
HomeController.cs
[RoutePrefix("api/foo")]
public class HomeController : ApiController
{
[Route("bar")]
[HttpPut]
public async Task<IHttpActionResult> Put()
{
await Task.Delay(200);
return Ok();
}
}
PUT http://localhost:56952/api/foo/bar
On average 1 of 5 cancelled requests end with 500 when cancelled after 10ms. The response code is accessible from server logs Application Insights or Output Window in VS when logged. The client will not receive the response code, because the connection is closed before any response code is returned.
UPDATE 2
Telemetry from Application Insights
I am considering this as a bug in .Net Framework. I have written a workaround to end the currently executing request when the specified criterion are met:
Cancellation is requested from the client
Client is not connected
Handling should occur only before the ExecuteRequestHandler event
public class CancellationHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.OnExecuteRequestStep(OnExecuteRequestStep);
}
private void OnExecuteRequestStep(HttpContextBase context, Action step)
{
if (context.Response.StatusCode != 0
&& context.Response.ClientDisconnectedToken.IsCancellationRequested
&& !context.Response.IsClientConnected
&& (int)context.CurrentNotification < (int)RequestNotification.ExecuteRequestHandler)
{
context.Response.StatusCode = 0;
context.ApplicationInstance.CompleteRequest();
}
step();
}
public void Dispose()
{
}
}
After the handling takes places, status code is changed to zero(just like in .net core) and skipping all remaining events in ASP.NET pipeline to EndRequest event. I have tested this implementation on production for a month and did not find requests resulting into 500 without a corresponding Exception record in logs.
Using tomcat 7, servlet 3.0, spring mvc3 with spring social, I get my class to listen sessions with;
public class AClass implements ApplicationContextAware, HttpSessionListener{
...
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
if (applicationContext instanceof WebApplicationContext) {
((WebApplicationContext) applicationContext).getServletContext().addListener(this);
}
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session created");
}
public void sessionDestroyed(HttpSessionEvent se){
System.out.println("session destroyed");
}
...
}
and I set the session-timeout to 1 minute in web.xml (I am sure it is working correctly)
When I open a page I get the 'session created' message but I never get 'session destroyed'.
If I refresh the page after 1 minute I get the 'session created' message again which claims that session is getting expired.
So the question is what am I getting wrong? Shouldn't sessionDestroyed method notify me when a session gets expired?
Yes, a session is destroyed when it times out or if you expire it programmatically using:
HttpSession.invalidate()
See this blog to ensure you are doing everything correctly.
Also, the servletcontainer will not immediately destroy sessions after exactly the timeout value. There is a background job which runs at certain time intervals like 5~15 minutes. So most likely you don't see destroyed line in the console immediately because of this reason.
My app receives an HTTP request, and in the middle of the pipeline, a call is made to another server for supporting information. The initial HTTP request can't continue through the pipeline until that response comes back. I can't use the awaitUninterruptability() from an I/O thread, so what's the best approach to make these calls so I don't block Netty's event loop, but put the client's pipeline on hold until my call out returns and I tell the pipeline to continue on?
Ryan this does not sound like a good idea..
I think you should better use something like that:
public class HttpHandler extends SimpleChannelUpstreamHandler{
#Override
public void messageReceived(final ChannelHandlerContext ctx, final MessageEvent e) throws Exception {
otherChannel.write(yourRequet).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
// once the write is done we can continue in the pipeline
ctx.sendUpstream(e);
}
});
// the event stops here to get processed
}
}
If you need to wait for the response then you will need to handle it in another SimpleChannelUpstreamHandler. But I think you get the idea..
I guess you need an ExecutionHandler.
I am developing custom HTTP server with netty 3.3.1.
I need to implement something like this
HTTP Server receives request
HTTP Server parses it and invokes HTTP request as a client to other machine
HTTP Server waits for the response of request sent in (2)
HTTP Server sends response to request from (1) based on what had received in (3)
It means that client request (2) has to behave as synchronous.
What I wrote is based on HttpSnoopClient example but it does not work, because I receive
java.lang.IllegalStateException:
await*() in I/O thread causes a dead lock or sudden performance drop. Use addListener() instead or call await*() from a different thread.
I've refactored the code from the example mentioned above and now it looks more less like this (starting from line 7f of HttpSnoopClient):
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
if (!future.isSuccess()) {
System.err.println("Cannot connect");
future.getCause().printStackTrace();
bootstrap.releaseExternalResources();
return;
}
System.err.println("Connected");
Channel channel = future.getChannel();
// Send the HTTP request.
channel.write(request);
channel.close();
// Wait for the server to close the connection.
channel.getCloseFuture().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
System.err.println("Disconnected");
bootstrap.releaseExternalResources(); // DOES NOT WORK?
}
});
}
});
}
}
The run() command from the above example is invoked in the messageReceived function of my herver handler.
So it became asynchronous and avoid await* functions. Request is invoked properly. But - for uknown reason for me - the line
bootstrap.releaseExternalResources(); // DOES NOT WORK?
does not work. It throws an exception saying that I cannot kill the thread I am currently using (which sounds reasonable, but still does not give me an answer how to do that in a different way).
I am also not sure is this a correct approach?
Maybe you can recommend a tutorial of such event programming techniques in netty? How to deal - in general - with a few asynchronous requests that has to be invoked in specified order and wait for each other?
Thank you,
If you really want to release the bootstrap on close you can do it like this:
channel.getCloseFuture().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
System.err.println("Disconnected");
new Thread(new Runnable() {
public void run() {
bootstrap.releaseExternalResources();
}
}).start();
}
});