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