Skip to content

Commit

Permalink
HTTP Pool data added to JMX management (#793)
Browse files Browse the repository at this point in the history
* Add HTTP connection pool info to JMX
Issue:104837

* Call creation and destruction of mbeans

* Various fixes

* Better positioning of beans in monitoring console

* Check used connections every 30 seconds

* Shutdown runnable when no longer needed

* Revert "Check used connections every 30 seconds"

This reverts commit a15eaa7.

* Set difference to find closed connections

* Destroy connection pool manager after cleanup

* Identify each http route by an unique id

* Various fixes

* Remove usage of custom connection pool

* Manage JMX operation in a single separate thread

* Remove usage of IdentifiableHttpRoute and prevent concurrency exception

* Use apache logger instead of system.out
  • Loading branch information
tomas-sexenian authored Nov 8, 2023
1 parent 62b3c40 commit fc148fd
Show file tree
Hide file tree
Showing 6 changed files with 381 additions and 294 deletions.
65 changes: 47 additions & 18 deletions java/src/main/java/com/genexus/internet/HttpClientJavaLib.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.*;
import com.genexus.ModelContext;
import com.genexus.util.IniFile;
import java.net.URI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.net.ssl.SSLContext;

import org.apache.http.*;
import com.genexus.CommonUtil;
import com.genexus.specific.java.*;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
Expand All @@ -43,17 +46,21 @@
import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.Logger;
import com.genexus.webpanels.HttpContextWeb;
import java.net.URI;

import javax.net.ssl.SSLContext;
import com.genexus.webpanels.HttpContextWeb;
import com.genexus.ModelContext;
import com.genexus.management.HTTPConnectionJMX;
import com.genexus.management.HTTPPoolJMX;
import com.genexus.util.IniFile;
import com.genexus.Application;
import com.genexus.CommonUtil;
import com.genexus.specific.java.*;

public class HttpClientJavaLib extends GXHttpClient {

Expand All @@ -75,12 +82,21 @@ private static void getPoolInstance() {
connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connManager.setMaxTotal((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_SIZE", "1000")));
connManager.setDefaultMaxPerRoute((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_PER_ROUTE", "1000")));

if (Application.isJMXEnabled())
HTTPPoolJMX.CreateHTTPPoolJMX(connManager);
}
else {
connManager.closeExpiredConnections();
}
}

@Override
protected void finalize() {
this.closeOpenedStreams();
executor.shutdown();
}

private ConnectionKeepAliveStrategy generateKeepAliveStrategy() {
return new ConnectionKeepAliveStrategy() {
@Override
Expand Down Expand Up @@ -110,7 +126,6 @@ public void setTimeout(int timeout)
}

private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(HttpClientJavaLib.class);

private static PoolingHttpClientConnectionManager connManager = null;
private Integer statusCode = 0;
private String reasonLine = "";
Expand All @@ -127,8 +142,9 @@ public void setTimeout(int timeout)
private static IniFile clientCfg = new ModelContext(ModelContext.getModelContextPackageClass()).getPreferences().getIniFile();
private static final String SET_COOKIE = "Set-Cookie";
private static final String COOKIE = "Cookie";

private java.util.Vector<InputStream> streamsToClose;
private static HashSet<HttpRoute> storedRoutes = new HashSet<>();


private void closeOpenedStreams()
{
Expand Down Expand Up @@ -599,8 +615,12 @@ public void execute(String method, String url) {
this.reasonLine = "";
}
finally {
if (getIsURL())
{
if (Application.isJMXEnabled()){
if (executor.isShutdown())
executor = Executors.newSingleThreadExecutor();
executor.submit(this::displayHTTPConnections);
}
if (getIsURL()) {
this.setHost(getPrevURLhost());
this.setBaseURL(getPrevURLbaseURL());
this.setPort(getPrevURLport());
Expand All @@ -611,6 +631,21 @@ public void execute(String method, String url) {
}
}

private static ExecutorService executor = Executors.newSingleThreadExecutor();
private synchronized void displayHTTPConnections(){
Iterator<HttpRoute> iterator = storedRoutes.iterator();
while (iterator.hasNext()) {
HttpRoute route = iterator.next();
HTTPConnectionJMX.DestroyHTTPConnectionJMX(route);
iterator.remove();
}

for (HttpRoute route : connManager.getRoutes()){
HTTPConnectionJMX.CreateHTTPConnectionJMX(route);
storedRoutes.add(route);
}
}

public int getStatusCode() {
return statusCode;
}
Expand Down Expand Up @@ -738,10 +773,4 @@ public void cleanup() {
resetErrorsAndConnParams();
}

@Override
protected void finalize()
{
this.closeOpenedStreams();
}

}
41 changes: 41 additions & 0 deletions java/src/main/java/com/genexus/management/HTTPConnectionJMX.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.genexus.management;

import org.apache.http.conn.routing.HttpRoute;
import org.apache.logging.log4j.Logger;

public class HTTPConnectionJMX implements HTTPConnectionJMXBean{

private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPConnectionJMX.class);

HttpRoute httpRoute;

public HTTPConnectionJMX(HttpRoute httpRoute) {
this.httpRoute = httpRoute;
}

static public void CreateHTTPConnectionJMX(HttpRoute connection) {
try {
MBeanUtils.createMBean(connection);
}
catch (Exception e) {
log.error("Failed to register HTTP connection MBean.", e);
}
}

static public void DestroyHTTPConnectionJMX(HttpRoute connection) {
try {
MBeanUtils.destroyMBean(connection);
}
catch (Exception e) {
log.error("Failed to destroy HTTP connection MBean.", e);
}
}

public int getPort() {
return httpRoute.getTargetHost().getPort();
}

public String getHost() {
return httpRoute.getTargetHost().getHostName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.genexus.management;

public interface HTTPConnectionJMXBean {
int getPort();
String getHost();
}
58 changes: 58 additions & 0 deletions java/src/main/java/com/genexus/management/HTTPPoolJMX.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.genexus.management;

import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;

import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.logging.log4j.Logger;
public class HTTPPoolJMX extends NotificationBroadcasterSupport implements HTTPPoolJMXMBean{

private long sequenceNumber=0;
PoolingHttpClientConnectionManager connectionPool;
private long lastUserWaitingForLongTimeNotif = 0L;
private long lastPoollsFullNotif = 0L;
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPPoolJMX.class);

public HTTPPoolJMX(PoolingHttpClientConnectionManager connectionPool) {
this.connectionPool = connectionPool;
}

static public void CreateHTTPPoolJMX(PoolingHttpClientConnectionManager httpConnectionPool) {
try {
MBeanUtils.createMBean(httpConnectionPool);
}
catch(Exception e) {
log.error("Failed to register HTTP connection pool MBean.", e);
}
}

public int getNumberOfConnectionsInUse(){
return connectionPool.getTotalStats().getLeased();
}

public int getNumberOfRequestsWaiting(){
return connectionPool.getTotalStats().getPending();
}

public int getNumberOfAvailableConnections(){
return connectionPool.getTotalStats().getAvailable();
}

public int getMaxNumberOfConnections(){
return connectionPool.getTotalStats().getMax();
}

public MBeanNotificationInfo[] getNotificationInfo() {
String[] types = new String[] {"com.genexus.managment.fullpool"};
String name = Notification.class.getName();
String description = "The Connection Pool does not have available connections ";
MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);

types = new String[] {"com.genexus.managment.longtimeuserwaiting"};
description = "User waiting a connection for a long time";
MBeanNotificationInfo info1 = new MBeanNotificationInfo(types, name, description);

return new MBeanNotificationInfo[] {info, info1};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.genexus.management;

public interface HTTPPoolJMXMBean {
int getNumberOfConnectionsInUse();
int getNumberOfRequestsWaiting();
int getNumberOfAvailableConnections();
int getMaxNumberOfConnections();
}
Loading

0 comments on commit fc148fd

Please sign in to comment.