Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] Question about behavior of WriteListener

Hi,

On Wed, Oct 19, 2016 at 12:12 PM, Christoph Läubrich
<laeubi@xxxxxxxxxxxxxx> wrote:
> I have a question about the usage/behavior of WriteListener because I
> encountered a strange problem: Writing works most of the time, but as soon
> as the data hit some magic size-limit it is truncated.
>
> I created a very simplified class like this:
>
> public class ByteArrayWriteListener implements WriteListener {
>
>   private ServletOutputStream stream;
>   private byte[] data;
>   private AsyncContext asyncContext;
>
>   public ByteArrayWriteListener(byte[] data, AsyncContext asyncContext,
> ServletOutputStream stream) {
>     this.data = data;
>     this.asyncContext = asyncContext;
>     this.stream = stream;
>   }
>
>   @Override
>   public void onError(Throwable t) {
>   }
>
>   @Override
>   public void onWritePossible() throws IOException {
>    stream.write(data);
>    asyncContext.complete();

Uh, no.

>   }
>
> }
>
> all data is written as a big bunch and then the AsyncContext is immediately
> completed (note that it doesn't matter if complete is called outside the
> write-listener).

That's wrong.

> This leads to the effect that the client simply gets only
> partial of the data when it grows up to a magic limit (maybe some response
> buffer size or so seem to depend on client load also...), setting the
> content-length prior to writing data has no effect. If I modify* the code
> that it checks (after the write) that the stream is ready then everything
> works.

Yep.

> Question: is it expected that a prior write is not completed if asyncContext
> is completed?

The semantic of write(), in case of async I/O, has changed so that it
does not guarantee that a write happens at all.
It could write 0 bytes, 1, N, or all of them.

Calling AsyncContext.complete() tells the container that you are done
writing, but you are actually not done until the write is actually
completed.

> I can't find in the Javadoc any hint that AsyncContext.complete() might stop
> any already issued writes, and would expect that it throws an exception like
> calling stream.flush() for example if not isReady was called before.
>
> Thanks in advance for any clarification :-)
>
> * Modified code:
>   @Override
>   public void onWritePossible() throws IOException {
>     if (!dataWritten) {
>       stream.write(data);
>       dataWritten = true;

Small nit on the variable naming:
Here it may not be true that the data is *written*.
It is true that you have a write *pending*.
It *may* be completed, but you can only know by calling isReady().

>     }
>     if (stream.isReady()) {
>       asyncContext.complete();
>     }
>   }

So yes, this code works because the write is not done twice thanks to
the flag, and AsyncContext.complete() is called when the write is
actually finished.

-- 
Simone Bordet
----
http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.


Back to the top