Skip to content

Instantly share code, notes, and snippets.

@haku
Last active February 24, 2016 16:28
Show Gist options
  • Save haku/4c5447c33850947c4862 to your computer and use it in GitHub Desktop.
Save haku/4c5447c33850947c4862 to your computer and use it in GitHub Desktop.
package foo;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.ConnectionProbe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Mitigation for https://java.net/jira/browse/GRIZZLY-1824
*
* Usage:
* server.getServerConfiguration().getMonitoringConfig().getConnectionConfig().addProbes(new ClosedConnectionCleaner());
*/
public class ClosedConnectionCleaner extends ConnectionProbe.Adapter implements Runnable {
private static final Logger LOG = LoggerFactory.getLogger(ClosedConnectionCleaner.class);
private final Set<Connection> connections = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>()));
private Field timeoutMillisField;
public ClosedConnectionCleaner(ScheduledExecutorService schEx) {
schEx.scheduleWithFixedDelay(this, 10, 10, TimeUnit.SECONDS);
}
@Override
public void onAcceptEvent(final Connection serverConnection, final Connection clientConnection) {
this.connections.add(clientConnection);
}
@Override
public void run() {
try {
int totalCount = 0;
int awaitingGc = 0;
int expiredCount = 0;
synchronized (this.connections) {
final Iterator<Connection> ittr = this.connections.iterator();
while (ittr.hasNext()) {
totalCount += 1;
final Connection conn = ittr.next();
final Object attr = conn.getAttributes().getAttribute("connection-idle-attribute");
if (this.timeoutMillisField == null) {
this.timeoutMillisField = attr.getClass().getDeclaredField("timeoutMillis");
this.timeoutMillisField.setAccessible(true);
}
if (!conn.isOpen()) {
awaitingGc += 1;
if ((long) this.timeoutMillisField.get(attr) > 1L) {
this.timeoutMillisField.set(attr, 1L); // Make it look like it would have timed out at 1ms past epoch.
expiredCount += 1;
}
}
}
}
if (totalCount > 0 || awaitingGc > 0 || expiredCount > 0) {
LOG.info("Connections: total={} awaitingGc={} expired={}", totalCount, awaitingGc, expiredCount);
}
}
catch (final Exception e) {
LOG.warn("oops.", e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment