|
44 | 44 | import eu.openanalytics.containerproxy.model.runtime.ProxyStatus; |
45 | 45 | import eu.openanalytics.containerproxy.util.DelegatingStreamSinkConduit; |
46 | 46 | import eu.openanalytics.containerproxy.util.DelegatingStreamSourceConduit; |
| 47 | +import eu.openanalytics.containerproxy.util.ChannelActiveListener; |
47 | 48 | import io.undertow.server.HttpServerExchange; |
48 | 49 | import io.undertow.server.protocol.http.HttpServerConnection; |
49 | 50 |
|
@@ -127,27 +128,38 @@ private void wrapChannels(StreamConnection streamConn) { |
127 | 128 | if (!streamConn.isOpen()) return; |
128 | 129 |
|
129 | 130 | ConduitStreamSinkChannel sinkChannel = streamConn.getSinkChannel(); |
130 | | - DelegatingStreamSinkConduit conduitWrapper = new DelegatingStreamSinkConduit(sinkChannel.getConduit(), null); |
| 131 | + ChannelActiveListener writeListener = new ChannelActiveListener(); |
| 132 | + DelegatingStreamSinkConduit conduitWrapper = new DelegatingStreamSinkConduit(sinkChannel.getConduit(), writeListener); |
131 | 133 | sinkChannel.setConduit(conduitWrapper); |
132 | 134 |
|
133 | 135 | ConduitStreamSourceChannel sourceChannel = streamConn.getSourceChannel(); |
134 | 136 | DelegatingStreamSourceConduit srcConduitWrapper = new DelegatingStreamSourceConduit(sourceChannel.getConduit(), data -> checkPong(data)); |
135 | 137 | sourceChannel.setConduit(srcConduitWrapper); |
136 | 138 |
|
137 | | - heartbeatExecutor.schedule(() -> sendPing(streamConn), getHeartbeatRate(), TimeUnit.MILLISECONDS); |
| 139 | + heartbeatExecutor.schedule(() -> sendPing(writeListener, streamConn), getHeartbeatRate(), TimeUnit.MILLISECONDS); |
138 | 140 | } |
139 | 141 |
|
140 | | - private void sendPing(StreamConnection streamConn) { |
| 142 | + private void sendPing(ChannelActiveListener writeListener, StreamConnection streamConn) { |
| 143 | + if (writeListener.isActive(getHeartbeatRate())) { |
| 144 | + // active means that data was written to the channel in the least heartbeat interval |
| 145 | + // therefore we don't send a ping now to not cause collisions |
| 146 | + |
| 147 | + // reschedule ping |
| 148 | + heartbeatExecutor.schedule(() -> sendPing(writeListener, streamConn), getHeartbeatRate(), TimeUnit.MILLISECONDS); |
| 149 | + // mark as we received a heartbeat |
| 150 | + heartbeatReceived(proxyId); |
| 151 | + return; |
| 152 | + } |
141 | 153 | if (!streamConn.isOpen()) return; |
142 | 154 |
|
143 | 155 | try { |
144 | | - streamConn.getSinkChannel().write(ByteBuffer.wrap(WEBSOCKET_PING)); |
| 156 | + ((DelegatingStreamSinkConduit) streamConn.getSinkChannel().getConduit()).writeWithoutNotifying(ByteBuffer.wrap(WEBSOCKET_PING)); |
145 | 157 | streamConn.getSinkChannel().flush(); |
146 | 158 | } catch (IOException e) { |
147 | 159 | // Ignore failure, keep trying as long as the stream connection is valid. |
148 | 160 | } |
149 | 161 |
|
150 | | - heartbeatExecutor.schedule(() -> sendPing(streamConn), getHeartbeatRate(), TimeUnit.MILLISECONDS); |
| 162 | + heartbeatExecutor.schedule(() -> sendPing(writeListener, streamConn), getHeartbeatRate(), TimeUnit.MILLISECONDS); |
151 | 163 | } |
152 | 164 |
|
153 | 165 | private void checkPong(byte[] response) { |
|
0 commit comments