You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Rossen Stoyanchev <rs...@vmware.com> on 2013/05/05 14:18:11 UTC

IOException from the response during an async request

When a request has been put into async mode (via request.startAsync), the response may remain open long after the initial container thread has exited. Meanwhile a non-container thread is allowed to write to the response but if an IOException occurs, there is obviously no way to report it to the client since the error implies we're unable to write to the response any more.

>From what I can see to complete the async request in this (or any async scenario) one has to call asyncContext.dispatch(), wait for the dispatch, and then call asyncContext.complete() in the dispatched thread, or let the dispatched thread complete. And this is true even if the IOException occurred in the brief period after startAsync but before the initial container thread has exited.

This is based on the Javadoc of asyncContext.complete() by the way:

* <p>It is legal to call this method any time after a call to
* {@link ServletRequest#startAsync()} or
* {@link ServletRequest#startAsync(ServletRequest, ServletResponse)},
* and before a call to one of the <tt>dispatch</tt> methods
* of this class. 

It seems rather convoluted for dealing with exceptions from the response especially in cases where the client has gone away, so I just wanted to confirm it's the correct way and the only way. 

Thanks,
Rossen

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: IOException from the response during an async request

Posted by Mark Thomas <ma...@apache.org>.
On 15/05/2013 20:35, Rossen Stoyanchev wrote:
> Mark,
> 
> While there is no response on the Servlet spec list, I have some follow-up
> questions:
> 
>> If you call complete() you'll end up with an IllegalStateException when
>> the error handler kicks in. You have to use dispatch(). The error handle
>> kicks in as soon as the dispatch() tries to write to the response.
> 
> Do you mean dispatch() + write to the response from within the dispatched
> thread thereby causing an error? I actually have no reason to write to the
> response at that point. I'm just trying to complete the async request and
> release any associated Servlet container resources.

Yes, the target of the dispatch() has to try and write something so the
error handler kicks in.

> I did try dispatch() and then complete() from within the dispatched thread.
> It leads to a similar ISE from AsyncStateMachine.

You shouldn't need to call complete(). Just try and write something and
let the container handle the resulting error.

> Lastly if I do call complete() without dispatch, thereby causing the ISE,
> does that actually complete the async request and release any container
> resources? I'm just trying to decide if this is something I can live with
> for now while the EG decides.

I haven't tested it but I don't believe it will. Something needs to
happen to get the request back on a container thread.

Mark


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: IOException from the response during an async request

Posted by Rossen Stoyanchev <rs...@gopivotal.com>.
Mark,

While there is no response on the Servlet spec list, I have some follow-up
questions:

> If you call complete() you'll end up with an IllegalStateException when
> the error handler kicks in. You have to use dispatch(). The error handle
> kicks in as soon as the dispatch() tries to write to the response.

Do you mean dispatch() + write to the response from within the dispatched
thread thereby causing an error? I actually have no reason to write to the
response at that point. I'm just trying to complete the async request and
release any associated Servlet container resources.

I did try dispatch() and then complete() from within the dispatched thread.
It leads to a similar ISE from AsyncStateMachine.

Lastly if I do call complete() without dispatch, thereby causing the ISE,
does that actually complete the async request and release any container
resources? I'm just trying to decide if this is something I can live with
for now while the EG decides.

Thanks,
Rossen

Re: IOException from the response during an async request

Posted by Rossen Stoyanchev <rs...@gopivotal.com>.
The questions have been posted on the Servlet spec user list:
https://java.net/projects/servlet-spec/lists/users/archive/2013-05/message/5




On Sun, May 5, 2013 at 1:34 PM, Mark Thomas <ma...@apache.org> wrote:

> On 05/05/2013 17:29, Rossen Stoyanchev wrote:
> >
> > ----- Original Message -----
> >> From: "Mark Thomas" <ma...@apache.org> To: "Tomcat Users List"
> >> <us...@tomcat.apache.org> Sent: Sunday, May 5, 2013 11:35:54 AM
> >> Subject: Re: IOException from the response during an async request
> >>
> >>> From what I can see to complete the async request in this (or
> >>> any async scenario) one has to call asyncContext.dispatch(), wait
> >>> for the dispatch, and then call asyncContext.complete() in the
> >>> dispatched thread, or let the dispatched thread complete. And
> >>> this is true even if the IOException occurred in the brief period
> >>> after startAsync but before the initial container thread has
> >>> exited.
> >>
> >> In the non-error case, you can call complete() or dispatch().
> >>
> >> The non-error case is (currently) different.
> >>
> >> If you call complete() you'll end up with an IllegalStateException
> >> when the error handler kicks in. You have to use dispatch(). The
> >> error handle kicks in as soon as the dispatch() tries to write to
> >> the response.
> >
> > I have no need to write to the response. I know it blew up and am
> > trying to find a way to complete the request.
> >
> > Javadoc for complete() says it is legal to call it without making
> > further qualifications. Based on that alone I would expect complete()
> > to just work.
>
> In the non-error case it does.
>
> The error handling for errors on non-container threads is not well
> specified.
>
> > I presume the error handler kicks as a result of the IOException from
> > the response?
>
> No. The IOException sets a flag that an error has occurred. Once the
> control returns to the container the error handling kicks in as soon as
> that flag is checked.
>
> > And it probably notifies listeners asynchronously
>
> No. Listeners are notified synchronously.
>
> > so by
> > the time it gets around to doing that, I've already caught the
> > exception and called complete().
>
> No. Calling complete() hands control back to the container.
>
> > If this is true there seems to be an
> > inherent race condition.
>
> The analysis is way off. There is no race condition here.
>
> > I.e. even if dispatch, couldn't the dispatch complete sooner?
>
> Potentially the error flag could be checked sooner for both complete()
> and dispatch(). However, I'm not sure at this point what affect that
> would have on the current error handling.
>
> > Given that onError handlers aren't going to do I/O
> > would, would it be feasible to call them synchronously?
>
> They are called synchronously. This is a single threaded ordering
> problem not a multi-threading timing problem.
>
> > Or at least
> > have some synchronization that holds up completion if error handlers
> > have not been notified.
>
> That solution is trying to solve a problem that doesn't exist.
>
> >> Some guidance from the EG would be good here. It does seem more
> >> natural that a call to complete() should be sufficient in this
> >> case. However, that appears to preclude the error handlers from
> >> firing since the description of error handlers describes the
> >> request completing after the handler is fired.
> >>
> >> Maybe: complete() - no error handler
> >> dispatch() - error handler
> >
> > From an application perspective, it would be best to aim for
> > consistent behavior for complete(). The dispatch doesn't give any
> > benefit for the application for the added complexity and effort.
> >
> >> One for the Servlet EG I think.
> >
> > It would be useful to clarify indeed. Are you posting the question or
> > should I?
>
> Go for it. The questions as I see them are:
>
> 1. What error handling, if any, is triggered if an Exception occurs
> during asynchronous processing (e.g. an IOException because the client
> dropped the connection)
> a) on a container thread
> b) on a non-container thread
>
> After our I'm leaning towards none for both.
>
> 2. After any such exception what mechanisms are available for the
> application to complete async processing?
>
> I'm leaning towards:
> complete() and dispatch()
>
> With dispatch likely to be a poor choice if there has been an IO error
> as the chances of being able to return anything to the user are slim
> (but if/when that does fail AsyncListener.onError() will be triggered as
> per the current spec).
>
> Essentially Tomcat does all of this apart from allowing complete()
> (because the error flag get checked).
>
> Mark
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

Re: IOException from the response during an async request

Posted by Mark Thomas <ma...@apache.org>.
On 05/05/2013 17:29, Rossen Stoyanchev wrote:
> 
> ----- Original Message -----
>> From: "Mark Thomas" <ma...@apache.org> To: "Tomcat Users List"
>> <us...@tomcat.apache.org> Sent: Sunday, May 5, 2013 11:35:54 AM 
>> Subject: Re: IOException from the response during an async request
>> 
>>> From what I can see to complete the async request in this (or
>>> any async scenario) one has to call asyncContext.dispatch(), wait
>>> for the dispatch, and then call asyncContext.complete() in the
>>> dispatched thread, or let the dispatched thread complete. And
>>> this is true even if the IOException occurred in the brief period
>>> after startAsync but before the initial container thread has
>>> exited.
>> 
>> In the non-error case, you can call complete() or dispatch().
>> 
>> The non-error case is (currently) different.
>> 
>> If you call complete() you'll end up with an IllegalStateException 
>> when the error handler kicks in. You have to use dispatch(). The
>> error handle kicks in as soon as the dispatch() tries to write to
>> the response.
> 
> I have no need to write to the response. I know it blew up and am
> trying to find a way to complete the request.
> 
> Javadoc for complete() says it is legal to call it without making
> further qualifications. Based on that alone I would expect complete()
> to just work.

In the non-error case it does.

The error handling for errors on non-container threads is not well
specified.

> I presume the error handler kicks as a result of the IOException from
> the response?

No. The IOException sets a flag that an error has occurred. Once the
control returns to the container the error handling kicks in as soon as
that flag is checked.

> And it probably notifies listeners asynchronously

No. Listeners are notified synchronously.

> so by
> the time it gets around to doing that, I've already caught the
> exception and called complete().

No. Calling complete() hands control back to the container.

> If this is true there seems to be an
> inherent race condition.

The analysis is way off. There is no race condition here.

> I.e. even if dispatch, couldn't the dispatch complete sooner?

Potentially the error flag could be checked sooner for both complete()
and dispatch(). However, I'm not sure at this point what affect that
would have on the current error handling.

> Given that onError handlers aren't going to do I/O
> would, would it be feasible to call them synchronously?

They are called synchronously. This is a single threaded ordering
problem not a multi-threading timing problem.

> Or at least
> have some synchronization that holds up completion if error handlers
> have not been notified.

That solution is trying to solve a problem that doesn't exist.

>> Some guidance from the EG would be good here. It does seem more 
>> natural that a call to complete() should be sufficient in this
>> case. However, that appears to preclude the error handlers from
>> firing since the description of error handlers describes the
>> request completing after the handler is fired.
>> 
>> Maybe: complete() - no error handler
>> dispatch() - error handler
> 
> From an application perspective, it would be best to aim for
> consistent behavior for complete(). The dispatch doesn't give any
> benefit for the application for the added complexity and effort.
> 
>> One for the Servlet EG I think.
> 
> It would be useful to clarify indeed. Are you posting the question or
> should I?

Go for it. The questions as I see them are:

1. What error handling, if any, is triggered if an Exception occurs
during asynchronous processing (e.g. an IOException because the client
dropped the connection)
a) on a container thread
b) on a non-container thread

After our I'm leaning towards none for both.

2. After any such exception what mechanisms are available for the
application to complete async processing?

I'm leaning towards:
complete() and dispatch()

With dispatch likely to be a poor choice if there has been an IO error
as the chances of being able to return anything to the user are slim
(but if/when that does fail AsyncListener.onError() will be triggered as
per the current spec).

Essentially Tomcat does all of this apart from allowing complete()
(because the error flag get checked).

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: IOException from the response during an async request

Posted by Rossen Stoyanchev <rs...@vmware.com>.
----- Original Message -----
> From: "Mark Thomas" <ma...@apache.org>
> To: "Tomcat Users List" <us...@tomcat.apache.org>
> Sent: Sunday, May 5, 2013 11:35:54 AM
> Subject: Re: IOException from the response during an async request
> 
> > From what I can see to complete the async request in this (or any
> > async scenario) one has to call asyncContext.dispatch(), wait for
> > the dispatch, and then call asyncContext.complete() in the dispatched
> > thread, or let the dispatched thread complete. And this is true
> > even if the IOException occurred in the brief period after startAsync
> > but before the initial container thread has exited.
> 
> In the non-error case, you can call complete() or dispatch().
> 
> The non-error case is (currently) different.
> 
> If you call complete() you'll end up with an IllegalStateException
> when the error handler kicks in. You have to use dispatch(). The error
> handle kicks in as soon as the dispatch() tries to write to the response.

I have no need to write to the response. I know it blew up and am trying to find a way to complete the request.

Javadoc for complete() says it is legal to call it without making further qualifications. Based on that alone I would expect complete() to just work.

I presume the error handler kicks as a result of the IOException from the response? And it probably notifies listeners asynchronously so by the time it gets around to doing that, I've already caught the exception and called complete(). If this is true there seems to be an inherent race condition. I.e. even if dispatch, couldn't the dispatch complete sooner? Given that onError handlers aren't going to do I/O would, would it be feasible to call them synchronously? Or at least have some synchronization that holds up completion if error handlers have not been notified.

> > This is based on the Javadoc of asyncContext.complete() by the way:
> > 
> > * <p>It is legal to call this method any time after a call to *
> > {@link ServletRequest#startAsync()} or * {@link
> > ServletRequest#startAsync(ServletRequest, ServletResponse)}, * and
> > before a call to one of the <tt>dispatch</tt> methods * of this
> > class.
> > 
> > It seems rather convoluted for dealing with exceptions from the
> > response especially in cases where the client has gone away, so I
> > just wanted to confirm it's the correct way and the only way.
> 
> Some guidance from the EG would be good here. It does seem more
> natural that a call to complete() should be sufficient in this case. However,
> that appears to preclude the error handlers from firing since the
> description of error handlers describes the request completing after
> the handler is fired.
> 
> Maybe:
> complete() - no error handler
> dispatch() - error handler

>From an application perspective, it would be best to aim for consistent behavior for complete(). The dispatch doesn't give any benefit for the application for the added complexity and effort.

> One for the Servlet EG I think.

It would be useful to clarify indeed. Are you posting the question or should I?

Thanks,
Rossen

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: IOException from the response during an async request

Posted by Mark Thomas <ma...@apache.org>.
On 05/05/2013 13:18, Rossen Stoyanchev wrote:
> 
> When a request has been put into async mode (via request.startAsync),
> the response may remain open long after the initial container thread
> has exited. Meanwhile a non-container thread is allowed to write to
> the response but if an IOException occurs, there is obviously no way
> to report it to the client since the error implies we're unable to
> write to the response any more.

Agreed.

> From what I can see to complete the async request in this (or any
> async scenario) one has to call asyncContext.dispatch(), wait for the
> dispatch, and then call asyncContext.complete() in the dispatched
> thread, or let the dispatched thread complete. And this is true even
> if the IOException occurred in the brief period after startAsync but
> before the initial container thread has exited.

In the non-error case, you can call complete() or dispatch().

The non-error case is (currently) different.

If you call complete() you'll end up with an IllegalStateException when
the error handler kicks in. You have to use dispatch(). The error handle
kicks in as soon as the dispatch() tries to write to the response.

> This is based on the Javadoc of asyncContext.complete() by the way:
> 
> * <p>It is legal to call this method any time after a call to *
> {@link ServletRequest#startAsync()} or * {@link
> ServletRequest#startAsync(ServletRequest, ServletResponse)}, * and
> before a call to one of the <tt>dispatch</tt> methods * of this
> class.
> 
> It seems rather convoluted for dealing with exceptions from the
> response especially in cases where the client has gone away, so I
> just wanted to confirm it's the correct way and the only way.

Some guidance from the EG would be good here. It does seem more natural
that a call to complete() should be sufficient in this case. However,
that appears to preclude the error handlers from firing since the
description of error handlers describes the request completing after the
handler is fired.

Maybe:
complete() - no error handler
dispatch() - error handler

One for the Servlet EG I think.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org