Receiving SocketTimeoutException when using Jira Rest Java Client
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Summary
Certain requests to Jira using the Jira Rest java Client (JRJC) result in SocketTimeoutException when they exceed 20 seconds (20,000 milliseconds).
The below snippet can be seen in the error stacktrace:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: java.net.SocketTimeoutException: 20,000 milliseconds timeout on connection http-outgoing-0 [ACTIVE]] with root cause
Environment
Jira Core 7.x and 8.x
All versions of JRJC (up to 5.2.1 at least)
Diagnosis
The only evidence we need is the SocketTimeoutMessage mentioning the 20,000 milliseconds in the stacktrace:
java.net.SocketTimeoutException: 20,000 milliseconds timeout on connection
Cause
JRJC has some hard-coded HTTP request properties, the socketTimeout
included:
public static final String OPTION_PROPERTY_PREFIX = "com.atlassian.httpclient.options";
public static final String OPTION_THREAD_WORK_QUEUE_LIMIT = "com.atlassian.httpclient.options.threadWorkQueueLimit";
private final Logger log = LoggerFactory.getLogger(this.getClass());
private List<String> blacklistedAddresses;
private String threadPrefix = "httpclient";
private boolean ignoreCookies = false;
private int ioThreadCount = Integer.getInteger("com.atlassian.httpclient.options.ioThreadCount", 10);
private long ioSelectInterval = (long)Integer.getInteger("com.atlassian.httpclient.options.ioSelectInterval", 1000);
private int threadWorkQueueLimit = Integer.getInteger("com.atlassian.httpclient.options.threadWorkQueueLimit", 256);
private long connectionTimeout = 5000L;
private long socketTimeout = 20000L;
private long requestTimeout = 90000L;
private int maxTotalConnections = 20;
private int maxConnectionsPerHost = 20;
private long connectionPoolTimeToLive = 30000L;
private long maxCacheObjectSize = 102400L;
private int maxCacheEntries = 100;
private long maxEntitySize = 104857600L;
private long leaseTimeout = 600000L;
private int maxCallbackThreadPoolSize = 16;
private boolean trustSelfSignedCertificates = false;
private Consumer<Request> requestPreparer = (request) -> {
};
private String userAgent = "Default";
private ExecutorService callbackExecutor;
private ProxyOptions proxyOptions = ProxyOptionsBuilder.create().build();
private HostResolver hostResolver;
Solution
As of version 5.2.1, JRJC doesn't allow the configuration of any of the HTTP Options above.
Two workarounds have been shared on the Community, both consisting of writing custom classes to replace those internal to JRJC:
- Write 2 custom classes (CustomAsynchronousJiraRestClientFactory and CustomAsynchronousHttpClientFactory) to substitute the default JRJC's
- Write one custom class with use of Apache libs (CustomBasicHttpAuthenticationHandlerImpl) and use the
AsynchronousJiraRestClientFactory.createWithAuthenticationHandler(url, handler)
method
Both sample implementations can be seen in the Community thread.
As of Jul 2021, JRJC is still not under active development and we're unable to forecast when such improvements will be implemented.
This request is tracked on