Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the logic of GoAway frame handling in the client side #1833

Merged
merged 58 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
9a8e135
[Automated] Update the native jar versions
dilanSachi Dec 15, 2023
e1c88f8
Add stream goaway fix
dilanSachi Jan 2, 2024
cefd167
Merge branch 'master' into goaway-fix
dilanSachi Jan 2, 2024
8f4cea4
[Automated] Update the native jar versions
dilanSachi Jan 3, 2024
1da43d0
Remove client channel after goaway
dilanSachi Jan 4, 2024
5a76cb7
Add native test cases
dilanSachi Jan 4, 2024
370d737
Merge branch 'master' into goaway-fix
dilanSachi Jan 4, 2024
2d14863
Add license headers and comments
dilanSachi Jan 4, 2024
505544b
Fix line lengths
dilanSachi Jan 5, 2024
3f37115
Add rst test cases
dilanSachi Jan 7, 2024
f3cd6f9
Add rst frame fix
dilanSachi Jan 7, 2024
0f72561
Fix line lengths
dilanSachi Jan 7, 2024
40ded00
Fix test cases
dilanSachi Jan 8, 2024
e2a479e
Merge branch 'master' into goaway-fix
dilanSachi Jan 9, 2024
be287b5
Update test cases
dilanSachi Jan 9, 2024
6dac82d
Update goaway test case
dilanSachi Jan 9, 2024
1014fd2
Check exhausted before returning to pool
dilanSachi Jan 9, 2024
1e52513
Remove unused imports
dilanSachi Jan 9, 2024
e5ad5d8
Add a locking mechanism for conn manager
dilanSachi Jan 10, 2024
21a05d5
Update test cases
dilanSachi Jan 10, 2024
78f6a78
Merge branch 'master' into goaway-fix
dilanSachi Jan 10, 2024
a72df1b
Fix spotbug
dilanSachi Jan 10, 2024
52b9cfb
Merge branch 'master' into goaway-fix
dilanSachi Jan 11, 2024
5989f14
Update test name
dilanSachi Jan 11, 2024
c0d266c
Add connection timeout logic
dilanSachi Jan 16, 2024
2b2e427
Remove unnecessary print statements
dilanSachi Jan 16, 2024
ee3d31c
Add test case for conn timeout
dilanSachi Jan 17, 2024
be0b2be
Rename class
dilanSachi Jan 17, 2024
6bb8531
Catch create stream error
dilanSachi Jan 17, 2024
5ee83dd
Update test cases
dilanSachi Jan 17, 2024
9a239bb
Remove goaway received connections from channelpool
dilanSachi Jan 17, 2024
f6b5cbd
Merge upstream branch
dilanSachi Jan 17, 2024
d570f07
Remove redundant configs
dilanSachi Jan 17, 2024
a6006f2
Remove redundant pool object validation
dilanSachi Jan 17, 2024
197fbcc
Fix line length
dilanSachi Jan 17, 2024
ceaad83
Update test case name
dilanSachi Jan 17, 2024
7facc85
Improve codebase
dilanSachi Jan 17, 2024
a297fcc
Update changelog.md
dilanSachi Jan 17, 2024
60bd19b
Update test cases and implementation
dilanSachi Jan 18, 2024
dc64c1f
Fix test case failure
dilanSachi Jan 18, 2024
2c024cc
Add goaway rststream events to the state machine
dilanSachi Jan 18, 2024
964f553
Add suggestions from review comments
dilanSachi Jan 19, 2024
2256837
Update class name
dilanSachi Jan 19, 2024
be1c459
Merge branch 'master' into goaway-fix
dilanSachi Jan 19, 2024
e1755c9
Add test case for latch hang
dilanSachi Jan 19, 2024
ac88d61
Merge branch 'fix-error-hang' of https://github.com/dilanSachi/module…
dilanSachi Jan 19, 2024
0f8cb19
Format test case
dilanSachi Jan 19, 2024
c84f2ad
Merge branch 'master' into goaway-fix
dilanSachi Jan 19, 2024
78bba5d
[Automated] Update the native jar versions
dilanSachi Jan 19, 2024
00f8ff3
Add check for channel removal
dilanSachi Jan 23, 2024
d8c34de
Merge branch 'goaway-fix' of https://github.com/dilanSachi/module-bal…
dilanSachi Jan 23, 2024
dbdd12e
Merge branch 'master' into goaway-fix
dilanSachi Jan 23, 2024
087805a
Update http2 connection evict logic
dilanSachi Jan 24, 2024
feeca1f
Fix review comments
dilanSachi Jan 25, 2024
a2efd71
Merge branch 'master' into goaway-fix
dilanSachi Jan 25, 2024
29f2e6e
Update stale eviction variables
dilanSachi Jan 26, 2024
dd9c755
Set configurable values to pool config
dilanSachi Jan 29, 2024
e48aca0
Update changelog.md
dilanSachi Jan 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ballerina/http_client_connection_pool.bal
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ configurable int maxActiveConnections = -1;
configurable int maxIdleConnections = 100;
configurable decimal waitTime = 30;
configurable int maxActiveStreamsPerConnection = 100;
configurable decimal minEvictableIdleTime = 300;
configurable decimal timeBetweenEvictionRuns = 30;
configurable decimal minIdleTimeInStaleState = 300;
configurable decimal timeBetweenStaleEviction = 30;

# Configurations for managing HTTP client connection pool.
#
Expand All @@ -29,14 +33,22 @@ configurable int maxActiveStreamsPerConnection = 100;
# + maxActiveStreamsPerConnection - Maximum active streams per connection. This only applies to HTTP/2. Default value is 100
# + minEvictableIdleTime - Minimum evictable time for an idle connection in seconds. Default value is 5 minutes
# + timeBetweenEvictionRuns - Time between eviction runs in seconds. Default value is 30 seconds
# + minIdleTimeInStaleState - Minimum time in seconds for a connection to be kept open which has received a GOAWAY.
# This only applies for HTTP/2. Default value is 5 minutes. If the value is set to -1,
# the connection will be closed after all in-flight streams are completed
# + timeBetweenStaleEviction - Time between the connection stale eviction runs in seconds. This only applies for HTTP/2.
# Default value is 30 seconds
public type PoolConfiguration record {|
int maxActiveConnections = maxActiveConnections;
int maxIdleConnections = maxIdleConnections;
decimal waitTime = waitTime;
int maxActiveStreamsPerConnection = maxActiveStreamsPerConnection;
decimal minEvictableIdleTime = 300;
decimal timeBetweenEvictionRuns = 30;
decimal minIdleTimeInStaleState = 300;
dilanSachi marked this conversation as resolved.
Show resolved Hide resolved
decimal timeBetweenStaleEviction = 30;
dilanSachi marked this conversation as resolved.
Show resolved Hide resolved
|};

//This is a hack to get the global map initialized, without involving locking.
class ConnectionManager {
public PoolConfiguration & readonly poolConfig = {};
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

### Added
- [Expose HTTP connection eviction configurations in the client level](https://github.com/ballerina-platform/ballerina-library/issues/5951)
- [Added a way to handle GoAway frames in HTTP/2 clients](https://github.com/ballerina-platform/ballerina-library/issues/4806)
dilanSachi marked this conversation as resolved.
Show resolved Hide resolved

### Fixed
- [Remove unused import from Http2StateUtil](https://github.com/ballerina-platform/ballerina-library/issues/5966)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,10 @@ public final class HttpConstants {
"minEvictableIdleTime");
public static final BString CONNECTION_POOLING_TIME_BETWEEN_EVICTION_RUNS = StringUtils.fromString(
"timeBetweenEvictionRuns");
public static final BString CONNECTION_POOLING_IDLE_TIME_STALE_STATE = StringUtils.fromString(
"minIdleTimeInStaleState");
public static final BString CONNECTION_POOLING_TIME_BETWEEN_STALE_CHECK_RUNS = StringUtils.fromString(
"timeBetweenStaleEviction");
public static final String HTTP_CLIENT_CONNECTION_POOL = "PoolConfiguration";
public static final String CONNECTION_MANAGER = "ConnectionManager";
public static final int POOL_CONFIG_INDEX = 1;
Expand Down
17 changes: 15 additions & 2 deletions native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -1359,8 +1359,21 @@ public static void populatePoolingConfig(BMap poolRecord, PoolConfiguration pool

double timeBetweenEvictionRuns =
((BDecimal) poolRecord.get(HttpConstants.CONNECTION_POOLING_TIME_BETWEEN_EVICTION_RUNS)).floatValue();
poolConfiguration.setTimeBetweenEvictionRuns(
timeBetweenEvictionRuns < 0 ? 0 : (long) timeBetweenEvictionRuns * 1000);
if (timeBetweenEvictionRuns > 0) {
poolConfiguration.setTimeBetweenEvictionRuns((long) timeBetweenEvictionRuns * 1000);
}

double minIdleTimeInStaleState =
((BDecimal) poolRecord.get(HttpConstants.CONNECTION_POOLING_IDLE_TIME_STALE_STATE)).floatValue();
poolConfiguration.setMinIdleTimeInStaleState(minIdleTimeInStaleState < -1 ? -1 :
(long) minEvictableIdleTime * 1000);

double timeBetweenStaleEviction =
((BDecimal) poolRecord.get(HttpConstants.CONNECTION_POOLING_TIME_BETWEEN_STALE_CHECK_RUNS))
.floatValue();
if (timeBetweenStaleEviction > 0) {
poolConfiguration.setTimeBetweenStaleEviction((long) timeBetweenStaleEviction * 1000);
}
}

private static int validateConfig(long value, String configName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,8 @@ public final class Constants {
= "Idle timeout triggered before initiating outbound request";
public static final String IDLE_TIMEOUT_TRIGGERED_WHILE_WRITING_OUTBOUND_REQUEST_HEADERS
= "Idle timeout triggered while writing outbound request headers";
public static final String IDLE_TIMEOUT_TRIGGERED_WHILE_SENDING_RST_STREAM
= "Idle timeout triggered while sending RST_STREAM frame";
public static final String IDLE_TIMEOUT_TRIGGERED_WHILE_WRITING_OUTBOUND_REQUEST_BODY
= "Idle timeout triggered while writing outbound request entity body";
public static final String IDLE_TIMEOUT_TRIGGERED_BEFORE_INITIATING_INBOUND_RESPONSE
Expand Down Expand Up @@ -386,6 +388,8 @@ public final class Constants {
= "Remote host closed the connection before initiating outbound request";
public static final String REMOTE_SERVER_CLOSED_WHILE_WRITING_OUTBOUND_REQUEST_HEADERS
= "Remote host closed the connection while writing outbound request headers";
public static final String REMOTE_SERVER_CLOSED_WHILE_SENDING_RST_STREAM
= "Remote host closed the connection while sending RST_STREAM frame";
public static final String REMOTE_SERVER_CLOSED_WHILE_WRITING_OUTBOUND_REQUEST_BODY
= "Remote host closed the connection while writing outbound request entity body";
public static final String REMOTE_SERVER_CLOSED_BEFORE_INITIATING_INBOUND_RESPONSE
Expand All @@ -396,6 +400,32 @@ public final class Constants {
= "Remote host closed the connection while reading inbound response body";
public static final String REMOTE_SERVER_CLOSED_BEFORE_READING_100_CONTINUE_RESPONSE
= "Remote host closed the connection before reading 100 continue response";
// Server GOAWAY error scenarios
public static final String REMOTE_SERVER_SENT_GOAWAY_WHILE_WRITING_OUTBOUND_REQUEST_HEADERS
= "Remote host sent GOAWAY while writing outbound request headers";
public static final String REMOTE_SERVER_SENT_GOAWAY_WHILE_SENDING_RST_STREAM
= "Remote host sent GOAWAY while sending RST_STREAM frame";
public static final String REMOTE_SERVER_SENT_GOAWAY_WHILE_WRITING_OUTBOUND_REQUEST_BODY
= "Remote host sent GOAWAY while writing outbound request entity body";
public static final String REMOTE_SERVER_SENT_GOAWAY_BEFORE_INITIATING_INBOUND_RESPONSE
= "Remote host sent GOAWAY before initiating inbound response";
public static final String REMOTE_SERVER_SENT_GOAWAY_WHILE_READING_INBOUND_RESPONSE_HEADERS
= "Remote host sent GOAWAY while reading inbound response headers";
public static final String REMOTE_SERVER_SENT_GOAWAY_WHILE_READING_INBOUND_RESPONSE_BODY
= "Remote host sent GOAWAY while reading inbound response body";
// Server send RST_STREAM error scenarios
public static final String REMOTE_SERVER_SENT_RST_STREAM_WHILE_WRITING_OUTBOUND_REQUEST_HEADERS
= "Remote host sent RST_STREAM while writing outbound request headers";
public static final String REMOTE_SERVER_SENT_RST_STREAM_WHILE_SENDING_RST_STREAM
= "Remote host sent RST_STREAM while sending RST_STREAM frame";
public static final String REMOTE_SERVER_SENT_RST_STREAM_WHILE_WRITING_OUTBOUND_REQUEST_BODY
= "Remote host sent RST_STREAM while writing outbound request entity body";
public static final String REMOTE_SERVER_SENT_RST_STREAM_BEFORE_INITIATING_INBOUND_RESPONSE
= "Remote host sent RST_STREAM before initiating inbound response";
public static final String REMOTE_SERVER_SENT_RST_STREAM_WHILE_READING_INBOUND_RESPONSE_HEADERS
= "Remote host sent RST_STREAM while reading inbound response headers";
public static final String REMOTE_SERVER_SENT_RST_STREAM_WHILE_READING_INBOUND_RESPONSE_BODY
= "Remote host sent RST_STREAM while reading inbound response body";

public static final String REMOTE_CLIENT_TO_HOST_CONNECTION_CLOSED
= "Connection between remote client and host is closed";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public HttpResponseFuture send(OutboundMsgHolder outboundMsgHolder, HttpCarbonMe
this.configHashCode);
if (http2) {
// See whether an already upgraded HTTP/2 connection is available
Http2ClientChannel activeHttp2ClientChannel = http2ConnectionManager.borrowChannel(route);
Http2ClientChannel activeHttp2ClientChannel = http2ConnectionManager.fetchChannel(route);

if (activeHttp2ClientChannel != null) {
outboundMsgHolder.setHttp2ClientChannel(activeHttp2ClientChannel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,11 @@
* @throws Http2Exception if a protocol-related error occurred
*/
private static void createStream(Http2Connection conn, int streamId) throws Http2Exception {
conn.local().createStream(streamId, false);
try {
conn.local().createStream(streamId, false);
} catch (Http2Exception.StreamException exception) {
throw new Http2Exception(exception.error(), "Error occurred while creating stream", exception);

Check warning on line 376 in native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/states/Http2StateUtil.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/states/Http2StateUtil.java#L375-L376

Added lines #L375 - L376 were not covered by tests
}
if (LOG.isDebugEnabled()) {
LOG.debug("Stream created streamId: {}", streamId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ private void configureSslForHttp2(SocketChannel ch, ChannelPipeline clientPipeli
sslConfig.getCacheSize()));
}
}
clientPipeline.addLast(new Http2PipelineConfiguratorForClient(targetHandler, connectionAvailabilityFuture));
clientPipeline.addLast(
new ALPNClientHandler(targetHandler, connectionAvailabilityFuture));
clientPipeline
.addLast(Constants.HTTP2_EXCEPTION_HANDLER, new Http2ExceptionHandler(http2ConnectionHandler));
}
Expand Down Expand Up @@ -329,13 +330,13 @@ public void setHttp2ClientChannel(Http2ClientChannel http2ClientChannel) {
/**
* A handler to create the pipeline based on the ALPN negotiated protocol.
*/
class Http2PipelineConfiguratorForClient extends ApplicationProtocolNegotiationHandler {
class ALPNClientHandler extends ApplicationProtocolNegotiationHandler {

private TargetHandler targetHandler;
private ConnectionAvailabilityFuture connectionAvailabilityFuture;

public Http2PipelineConfiguratorForClient(TargetHandler targetHandler,
ConnectionAvailabilityFuture connectionAvailabilityFuture) {
public ALPNClientHandler(TargetHandler targetHandler,
ConnectionAvailabilityFuture connectionAvailabilityFuture) {
super(ApplicationProtocolNames.HTTP_1_1);
this.targetHandler = targetHandler;
this.connectionAvailabilityFuture = connectionAvailabilityFuture;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public ConnectionManager(PoolConfiguration poolConfiguration) {
globalConnPool = new ConcurrentHashMap<>();
globalFactoryObjects = new ConcurrentHashMap<>();
http2ConnectionManager = new Http2ConnectionManager(poolConfiguration);
connectionManagerId = "-" + UUID.randomUUID().toString();
connectionManagerId = "-" + UUID.randomUUID();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public class PoolConfiguration {
private int eventGroupExecutorThreads = 15;
private long maxWaitTime = 60000L;
private int http2MaxActiveStreamsPerConnection = Integer.MAX_VALUE;
private long minIdleTimeInStaleState = 300000;
private long timeBetweenStaleEviction = 30000;

public PoolConfiguration() {
}
Expand Down Expand Up @@ -142,4 +144,20 @@ public int getHttp2MaxActiveStreamsPerConnection() {
public void setHttp2MaxActiveStreamsPerConnection(int http2MaxActiveStreamsPerConnection) {
this.http2MaxActiveStreamsPerConnection = http2MaxActiveStreamsPerConnection;
}

public long getMinIdleTimeInStaleState() {
return minIdleTimeInStaleState;
}

public void setMinIdleTimeInStaleState(long minIdleTimeInStaleState) {
this.minIdleTimeInStaleState = minIdleTimeInStaleState;
}

public long getTimeBetweenStaleEviction() {
return timeBetweenStaleEviction;
}

public void setTimeBetweenStaleEviction(long timeBetweenStaleEviction) {
this.timeBetweenStaleEviction = timeBetweenStaleEviction;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
}
Channel channel = http2ClientChannel.getChannel();
if (channel == null) { // if channel is not active, forget it and fetch next one
http2ClientChannels.remove(http2ClientChannel);
removeChannel(http2ClientChannel);

Check warning on line 82 in native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/http2/Http2ChannelPool.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/http2/Http2ChannelPool.java#L82

Added line #L82 was not covered by tests
return fetchTargetChannel();
}
// increment and get active stream count
Expand All @@ -89,7 +89,7 @@
return http2ClientChannel;
} else if (activeStreamCount == maxActiveStreams) { // no more streams except this one can be opened
http2ClientChannel.markAsExhausted();
http2ClientChannels.remove(http2ClientChannel);
removeChannel(http2ClientChannel);

Check warning on line 92 in native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/http2/Http2ChannelPool.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/http2/Http2ChannelPool.java#L92

Added line #L92 was not covered by tests
// When the stream count reaches maxActiveStreams, a new channel will be added only if the
// channel queue is empty. This process is synchronized as transport thread can return channels
// after being reset. If such channel is returned before the new CountDownLatch, the subsequent
Expand All @@ -104,7 +104,7 @@
}
return http2ClientChannel;
} else {
http2ClientChannels.remove(http2ClientChannel);
removeChannel(http2ClientChannel);

Check warning on line 107 in native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/http2/Http2ChannelPool.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/http2/Http2ChannelPool.java#L107

Added line #L107 was not covered by tests
return fetchTargetChannel(); // fetch the next one from the queue
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.ballerina.stdlib.http.transport.contract.Constants;
import io.ballerina.stdlib.http.transport.contractimpl.common.HttpRoute;
import io.ballerina.stdlib.http.transport.contractimpl.common.states.Http2MessageStateContext;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http2.Http2Connection;
Expand Down Expand Up @@ -60,6 +61,8 @@ public class Http2ClientChannel {
private int socketIdleTimeout = Constants.ENDPOINT_TIMEOUT;
private Map<String, Http2DataEventListener> dataEventListeners;
private StreamCloseListener streamCloseListener;
private long timeSinceMarkedAsStale = 0;
private AtomicBoolean isStale = new AtomicBoolean(false);

public Http2ClientChannel(Http2ConnectionManager http2ConnectionManager, Http2Connection connection,
HttpRoute httpRoute, Channel channel) {
Expand Down Expand Up @@ -253,7 +256,7 @@ void destroy() {
this.connection.removeListener(streamCloseListener);
inFlightMessages.clear();
promisedMessages.clear();
http2ConnectionManager.removeClientChannel(httpRoute, this);
removeFromConnectionPool();
}

/**
Expand All @@ -271,6 +274,10 @@ private void handleConnectionClose() {
}
}

ConcurrentHashMap<Integer, OutboundMsgHolder> getInFlightMessages() {
return inFlightMessages;
}

/**
* Listener which listen to the stream closure event.
*/
Expand All @@ -289,13 +296,50 @@ public void onStreamClosed(Http2Stream stream) {
activeStreams.decrementAndGet();
http2ClientChannel.getDataEventListeners().
forEach(dataEventListener -> dataEventListener.onStreamClose(stream.id()));
if (isExhausted.getAndSet(false)) {
if (!isStale.get() && isExhausted.getAndSet(false)) {
http2ConnectionManager.returnClientChannel(httpRoute, http2ClientChannel);
}
}

@Override
public void onGoAwayReceived(int lastStreamId, long errorCode, ByteBuf debugData) {
markAsStale();
http2ClientChannel.inFlightMessages.forEach((streamId, outboundMsgHolder) -> {
if (streamId > lastStreamId) {
http2ClientChannel.removeInFlightMessage(streamId);
activeStreams.decrementAndGet();
http2ClientChannel.getDataEventListeners().forEach(
dataEventListener -> dataEventListener.onStreamClose(streamId));
Http2MessageStateContext messageStateContext =
outboundMsgHolder.getRequest().getHttp2MessageStateContext();
if (messageStateContext != null) {
messageStateContext.getSenderState().handleServerGoAway(outboundMsgHolder);
}
}
});
}
}

void removeFromConnectionPool() {
http2ConnectionManager.removeClientChannel(httpRoute, this);
}

void markAsStale() {
synchronized (http2ConnectionManager) {
isStale.set(true);
http2ConnectionManager.markClientChannelAsStale(httpRoute, this);
}
}

boolean hasInFlightMessages() {
return !inFlightMessages.isEmpty();
}

void setTimeSinceMarkedAsStale(long timeSinceMarkedAsStale) {
this.timeSinceMarkedAsStale = timeSinceMarkedAsStale;
}

long getTimeSinceMarkedAsStale() {
return timeSinceMarkedAsStale;
}
}
Loading
Loading