You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法捕获AsynchronousJiraRestClientFactory的SSLHandshakeException,求解决及重试方案

解决AsynchronousJiraRestClientFactory无法捕获SSLHandshakeException并实现重试的问题

这个问题我之前也碰到过,核心原因确实和AsynchronousJiraRestClientFactory的异步特性有关——你当前的try/catch只能覆盖客户端初始化的同步阶段,而SSL握手这类实际的网络操作是在异步线程里执行的,自然不会被当前的catch块捕获到。下面给你两种可行的处理方案,附带重试逻辑:

方案一:同步阻塞式处理(适合需要立即获取客户端的场景)

通过触发一个简单的API调用(比如获取当前用户)来强制完成SSL握手,把异步操作转为同步阻塞,这样就能在try/catch里捕获到SSLHandshakeException,再包裹重试逻辑:

import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
import javax.net.ssl.SSLHandshakeException;
import java.net.URI;
import java.util.logging.Logger;

public class JiraClientCreator {
    private static final Logger logger = Logger.getLogger(JiraClientCreator.class.getName());

    public JiraRestClient createJiraClientWithRetry(String uri, String username, String password, int maxRetries) throws Exception {
        URI jiraServerUri = URI.create(uri);
        JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
        int retryCount = 0;

        while (retryCount < maxRetries) {
            try {
                // 初始化客户端(同步操作,不会触发SSL握手)
                JiraRestClient restClient = factory.createWithBasicHttpAuthentication(jiraServerUri, username, password);
                // 调用一个轻量API触发SSL握手,claim()会阻塞直到结果返回或抛出异常
                restClient.getMySelf().claim();
                logger.info("JIRA客户端创建成功");
                return restClient;
            } catch (SSLHandshakeException e) {
                retryCount++;
                logger.error("SSL握手失败,正在进行第 {} 次重试", retryCount, e);
                if (retryCount >= maxRetries) {
                    logger.error("达到最大重试次数,无法建立JIRA连接", e);
                    throw e;
                }
                // 重试前添加1秒延迟,避免频繁请求
                Thread.sleep(1000);
            } catch (Exception e) {
                logger.error("创建JIRA客户端时发生未知异常", e);
                throw e;
            }
        }
        throw new IllegalStateException("无法建立JIRA连接,已达到最大重试次数");
    }
}

关键说明:

  • restClient.getMySelf().claim():这一步是核心,因为createWithBasicHttpAuthentication只是初始化客户端对象,实际的SSL握手是在第一次发起API请求时才会执行。调用claim()会阻塞当前线程,等待异步操作完成,这样就能把异步异常转为同步抛出,被try/catch捕获。
  • 重试逻辑:用while循环控制重试次数,每次捕获到SSLHandshakeException就重试,直到达到上限。

方案二:异步回调式处理(适合非阻塞场景)

如果你的业务不需要立即获取客户端,可以用异步回调来处理异常和重试,避免阻塞主线程:

import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
import javax.net.ssl.SSLHandshakeException;
import java.net.URI;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;

public class AsyncJiraClientCreator {
    private static final Logger logger = Logger.getLogger(AsyncJiraClientCreator.class.getName());

    public void createJiraClientAsync(String uri, String username, String password, int maxRetries) {
        URI jiraServerUri = URI.create(uri);
        JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
        AtomicInteger retryCount = new AtomicInteger(0); // 用AtomicInteger保证线程安全

        Runnable createTask = () -> {
            try {
                JiraRestClient restClient = factory.createWithBasicHttpAuthentication(jiraServerUri, username, password);
                // 用whenComplete处理异步结果和异常
                restClient.getMySelf().whenComplete((user, throwable) -> {
                    if (throwable != null) {
                        if (throwable instanceof SSLHandshakeException && retryCount.get() < maxRetries) {
                            int currentRetry = retryCount.incrementAndGet();
                            logger.error("SSL握手失败,正在进行第 {} 次重试", currentRetry, throwable);
                            // 重新执行创建任务
                            createTask.run();
                        } else {
                            logger.error("创建JIRA客户端失败", throwable);
                            // 这里处理最终失败的逻辑,比如告警、记录等
                        }
                    } else {
                        logger.info("JIRA客户端创建成功,当前用户:{}", user.getDisplayName());
                        // 这里可以继续使用restClient进行后续业务操作
                    }
                });
            } catch (Exception e) {
                logger.error("初始化JIRA客户端时发生异常", e);
            }
        };

        // 启动首次创建任务
        createTask.run();
    }
}

关键说明:

  • whenComplete回调:异步操作完成后会触发这个回调,我们可以在这里判断异常类型,如果是SSLHandshakeException且未达到重试次数,就重新执行创建任务。
  • AtomicInteger:因为异步操作可能在不同线程执行,用原子类保证重试次数的线程安全。

额外注意事项

  • 先排查SSL证书问题:如果JIRA服务器使用的是自签名证书,即使重试也会一直失败,需要先把证书导入到JVM的信任库中,或者配置客户端信任该证书。
  • 调整重试参数:根据实际情况设置重试次数和延迟时间,避免过度重试给服务器造成压力。

内容的提问来源于stack exchange,提问作者Sameer Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:09:14