On 07/03/17 14:55, Mark Thomas wrote:
> On 07/03/17 11:03, Mark Thomas wrote:
>> On 07/03/17 08:28, Pesonen, Harri wrote:
>>> Hello, we have a problem that Tomcat WebSocket does not always send 
>>> asynchronous messages. This problem is random, and it has been reproduced 
>>> in Tomcat 8.5.6 and 8.5.11. Synchronized operations work fine, and also the 
>>> asynchronous operations work except in one special case. When there is a 
>>> big message that we want to send to client, we split it into 16 kB packets 
>>> for technical reasons, and then we send them very quickly after each other 
>>> using
>>>
>>> /**
>>> * Initiates the asynchronous transmission of a binary message. This method 
>>> returns before the message
>>> * is transmitted. Developers provide a callback to be notified when the 
>>> message has been
>>> * transmitted. Errors in transmission are given to the developer in the 
>>> SendResult object.
>>> *
>>> * @param data       the data being sent, must not be {@code null}.
>>> * @param handler the handler that will be notified of progress, must not be 
>>> {@code null}.
>>> * @throws IllegalArgumentException if either the data or the handler are 
>>> {@code null}.
>>> */
>>> void sendBinary(ByteBuffer data, SendHandler handler);
>>>
>>> Because there can be only one ongoing write to socket, we use Semaphore 
>>> that is released on the SendHandler callback:
>>>
>>> public void onResult(javax.websocket.SendResult result) {
>>>     semaphore.release();
>>>
>>> So the code to send is actually:
>>>
>>> semaphore.acquireUninterruptibly();
>>> async.sendBinary(buf, asyncHandler);
>>>
>>> This works fine in most cases. But when we send one 16 kB packet and then 
>>> immediately one smaller packet (4 kB), then randomly the smaller packet is 
>>> not actually sent, but only after we call
>>>
>>> async.sendPing(new byte[0])
>>>
>>> in another thread. sendPing() is called every 20 seconds to keep the 
>>> WebSocket connection alive. This means that the last packet gets extra 
>>> delay on client, which varies between 0 - 20 seconds.
>>>
>>> We have an easy workaround to the problem. If we call flushBatch() after 
>>> each sendBinary(), then it works great, but this means that the sending is 
>>> not actually asynchronous, because flushBatch() is synchronous.
>>> Also we should not be forced to call flushBatch(), because we are not 
>>> enabling batching. Instead we make sure that it is disabled:
>>>
>>> if (async.getBatchingAllowed()) {
>>>     async.setBatchingAllowed(false);
>>>
>>> So the working code is:
>>>
>>> semaphore.acquireUninterruptibly();
>>> async.sendBinary(buf, asyncHandler);
>>> async.flushBatch();
>>>
>>> Normally the code works fine without flushBatch(), if there is delay 
>>> between the messages, but when we send the messages right after each other, 
>>> then the last small message is not always sent immediately.
>>> I looked at the Apache WebSocket code, but it was not clear to me what is 
>>> happening there.
>>> Any ideas what is going on here? Any ideas how I could troubleshoot this 
>>> more?
>>
>> Thanks for providing such a clear description of the problem you are seeing.
>>
>> It sounds like there is a race condition somewhere in the WebSocket
>> code. With the detail you have provided, I think there is a reasonable
>> chance of finding via code inspection.
> 
> Some follow-up questions to help narrow the search.
> 
> This is server side, correct?
> 
> Are you using the compression extension? If yes, do you see the problem
> without it?
> 
> When you say "we split it into 16 kB packets" do you mean you split it
> into multiple WebSocket messages?
> 
> If you insert a short delay before sending the final 4kB does that
> reduce the frequency of the problem?

I've added a (disabled by default) test case to explore the issue
described based on my understanding. It passes for me (ignoring what
look like GC introduced delays) with NIO.

http://svn.apache.org/viewvc?rev=1785893&view=rev

What would be really helpful would be if you could use this as a basis
for providing a test case that demonstrates the problem you are seeing.

Thanks,

Mark


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

Reply via email to