poyger
poyger

Reputation: 666

java jira rest client timeout issue

I get java.net.SocketTimeoutException when searching in jira. How can I increase the timeout ?

Code:

JiraRestClientFactory restClientFactory = new AsynchronousJiraRestClientFactory();
SearchResult results = null;

try {
    URI uri = new URI(jira_url);
    restClient = restClientFactory.createWithBasicHttpAuthentication(uri, jira_username, jira_password);
    final SearchRestClient searchClient = restClient.getSearchClient();
    String jql = searchClient.getFilter(jira_filterid).get().getJql();
    // setting max result to 1000 and start with 0
    results = searchClient.searchJql(jql, 500, 0).claim();
    System.out.println("Took: " + stopWatch.toString() + " to find " + results.getTotal() + " case in jira filter with id " + jira_filterid);
} catch (Exception e) {
    e.printStackTrace();
    System.exit(1);
}
return results;

The searching should not take so long, i think it is when doing claim().

Exception:

java.lang.RuntimeException: java.net.SocketTimeoutException
    at com.google.common.base.Throwables.propagate(Throwables.java:160)
    at com.atlassian.httpclient.apache.httpcomponents.DefaultHttpClient$3.apply(DefaultHttpClient.java:256)
    at com.atlassian.httpclient.apache.httpcomponents.DefaultHttpClient$3.apply(DefaultHttpClient.java:249)
    at com.atlassian.util.concurrent.Promises$Of$2.apply(Promises.java:276)
    at com.atlassian.util.concurrent.Promises$Of$2.apply(Promises.java:272)
    at com.atlassian.util.concurrent.Promises$2.onFailure(Promises.java:167)
    at com.google.common.util.concurrent.Futures$4.run(Futures.java:1172)
    at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:297)
    at com.google.common.util.concurrent.ExecutionList.executeListener(ExecutionList.java:156)
    at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:145)
    at com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:202)
    at com.google.common.util.concurrent.SettableFuture.setException(SettableFuture.java:68)
    at com.atlassian.httpclient.apache.httpcomponents.SettableFuturePromiseHttpPromiseAsyncClient$1$2.run(SettableFuturePromiseHttpPromiseAsyncClient.java:59)
    at com.atlassian.httpclient.apache.httpcomponents.SettableFuturePromiseHttpPromiseAsyncClient$ThreadLocalDelegateRunnable$1.run(SettableFuturePromiseHttpPromiseAsyncClient.java:197)
    at com.atlassian.httpclient.apache.httpcomponents.SettableFuturePromiseHttpPromiseAsyncClient.runInContext(SettableFuturePromiseHttpPromiseAsyncClient.java:90)
    at com.atlassian.httpclient.apache.httpcomponents.SettableFuturePromiseHttpPromiseAsyncClient$ThreadLocalDelegateRunnable.run(SettableFuturePromiseHttpPromiseAsyncClient.java:192)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:680)
Caused by: java.net.SocketTimeoutException
    at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.timeout(HttpAsyncRequestExecutor.java:279)
    at org.apache.http.impl.nio.client.LoggingAsyncRequestExecutor.timeout(LoggingAsyncRequestExecutor.java:128)
    at org.apache.http.impl.nio.DefaultHttpClientIODispatch.onTimeout(DefaultHttpClientIODispatch.java:136)
    at org.apache.http.impl.nio.DefaultHttpClientIODispatch.onTimeout(DefaultHttpClientIODispatch.java:50)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.timeout(AbstractIODispatch.java:169)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.sessionTimedOut(BaseIOReactor.java:257)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.timeoutCheck(AbstractIOReactor.java:494)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.validate(BaseIOReactor.java:207)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:284)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:604)
    ... 1 more

Upvotes: 4

Views: 8265

Answers (4)

Yuliya Hancharenka
Yuliya Hancharenka

Reputation: 11

java.util.concurrent.Future class has V get(long timeout, TimeUnit unit).

Adding timeout helped me:

String jql = searchClient.getFilter(jira_filterid).get(120, TimeUnit.SECONDS).getJql();

Upvotes: 1

alizelzele
alizelzele

Reputation: 923

I can not Believe i had to got so deep to change it. you can use reflection to achieve it

    try (JiraRestClient client = clientFactory.createWithBasicHttpAuthentication(new URI(jira.getUrl()), jira.getUsername(), jira.getPassword())) {
        try {
            Field f1 = Class.forName("com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClient").getDeclaredField("httpClient");
            Field f2 = Class.forName("com.atlassian.jira.rest.client.internal.async.AtlassianHttpClientDecorator").getDeclaredField("httpClient");
            Field f3 = Class.forName("com.atlassian.httpclient.apache.httpcomponents.ApacheAsyncHttpClient").getDeclaredField("httpClient");
            Field f4 = Class.forName("org.apache.http.impl.client.cache.CachingHttpAsyncClient").getDeclaredField("backend");
            Field f5 = Class.forName("org.apache.http.impl.nio.client.InternalHttpAsyncClient").getDeclaredField("defaultConfig");
            Field f6 = Class.forName("org.apache.http.client.config.RequestConfig").getDeclaredField("socketTimeout");
            f1.setAccessible(true);
            f2.setAccessible(true);
            f3.setAccessible(true);
            f4.setAccessible(true);
            f5.setAccessible(true);
            f6.setAccessible(true);
            Object requestConfig = f5.get(f4.get(f3.get(f2.get(f1.get(client)))));
            f6.setInt(requestConfig, 120 * 1000);
            f1.setAccessible(false);
            f2.setAccessible(false);
            f3.setAccessible(false);
            f4.setAccessible(false);
            f5.setAccessible(false);
            f6.setAccessible(false);
        } catch (Exception ignore) {
        }
        // now you can start using it :)
    } catch (URISyntaxException | IOException e) {
        logger.error("invalid jira server address: " + jira.getUrl(), e);
        throw new RuntimeException("can not access jira server");
    }

it will buy you 120 seconds of socket time.

Upvotes: 2

ChrLipp
ChrLipp

Reputation: 15668

Disclaimer: i am using the Groovy programming language, but the syntax is very similar to Java, so you should be able to reuse the code (hint: in Groovy no semi-colons are needed, the return statement is optional, instead of variable declaration i am using def or final only).

I am using the following library versions (gradle style):

compile "com.atlassian.jira:jira-rest-java-client-core:4.0.0"
compile "com.atlassian.fugue:fugue:2.2.1"

Here we have the standard rest client definition:

JiraRestClient getJiraRestClient()
{
    // read user specific Jira password settings and build authentification
    final inputFile = new File("${System.getProperty('user.home')}/jiraSettings.json")
    final authInfo = new JsonSlurper().parseText(inputFile.text)

    // setting up the jira client
    def restClient = new AsynchronousJiraRestClientFactory()
        .createWithBasicHttpAuthentication(
            jiraServerUri,
            authInfo.jiraUser.toString(),
            authInfo.jiraPassword.toString())

    restClient
}

I dived into the createWithBasicHttpAuthentication function and extracted and adapted the code (only getClientOptions - I set the socket timeout to 45 seconds, look at HttpClientOptions default settings):

JiraRestClient getJiraRestClient()
{
    return new AsynchronousJiraRestClient(jiraServerUri, getHttpClient());
}

HttpClientOptions getClientOptions()
{
    def options = new HttpClientOptions();
    options.socketTimeout = 45000L;
    options
}

DisposableHttpClient getHttpClient()
{
    final DefaultHttpClientFactory defaultHttpClientFactory =
        new DefaultHttpClientFactory(new AsynchronousHttpClientFactory.NoOpEventPublisher(),
        new AsynchronousHttpClientFactory.RestClientApplicationProperties(jiraServerUri),
        new ThreadLocalContextManager() {
            @Override
            public Object getThreadLocalContext() {
                return null;
            }

            @Override
            public void setThreadLocalContext(Object context) {}

            @Override
            public void clearThreadLocalContext() {}
        });

    final HttpClient httpClient = defaultHttpClientFactory.create(getClientOptions())

    return new AtlassianHttpClientDecorator(httpClient, getAuthenticationHandler()) {
        @Override
        public void destroy() throws Exception {
            defaultHttpClientFactory.dispose(httpClient);
        }
    }
}

BasicHttpAuthenticationHandler getAuthenticationHandler()
{
    // read user specific Jira password settings and build authentification
    final inputFile = new File("${System.getProperty('user.home')}/jiraSettings.json")
    final authInfo = new JsonSlurper().parseText(inputFile.text)

    return new BasicHttpAuthenticationHandler(
        authInfo.jiraUser.toString(),
        authInfo.jiraPassword.toString())
}

The downside is that I might be forced to adapt this code when I switch to a new version of jira-rest-java-client, but I really need this because the timout is just to short, even with heavy use of paging.

Upvotes: 1

poyger
poyger

Reputation: 666

one workaround that seams to work is to take 100 result for each iteration and set startAt

results = searchClient.searchJql(jql, 100, 0).claim();
results1 = searchClient.searchJql(jql, 100, 100).claim();
results2 = searchClient.searchJql(jql, 100, 200).claim();

and so on.

Upvotes: 1

Related Questions