JetBrains AI 打零工(六)——程序运行时错误修复

处理程序运行时错误是一个耗时任务,对于 Java 工程来说尤其如此,JetBrains AI 的设计者也意识到了这点,提供了一些有效的运行时错误修复方案。

比如在本地运行时控制台、SSH 远程日志中都添加了一键修复的功能。在 Terminal 中快速回显错误日志相应的源代码,还可以直接向 AI Assistant 发起提问,日志上下文会被自动附带进去。错误修复的本质和开发新需求是一样的,都是领域知识的召回。如果不清楚代码需求背景和架构知识,只贴进去一段错误日志就容易出现幻觉。

如果没有投喂足够多的项目上下文知识并且对代码模块都不熟悉的情况下,借助 JetBrains AI 依然可以快速了解代码大致作用并解决错误。

1、No such file or directory

日志发现执行外部进程找不到文件,从线上日志中截取到如下错误日志:

java 复制代码
2025-06-19 11:17:21.785 [Thread-13] [ERROR] xxx.alarm.service.impl.AlarmServiceImpl:844 - 执行脚本失败:python: can't open file '/xxx/alarm/20250619111721.py': [Errno 2] No such file or directory

2025-06-19 11:17:21.788 [Thread-13] [ERROR] xxx.alarm.service.impl.AlarmServiceImpl:713 - 发送脚本失败,error:
xxx.common.exception.ServiceException: python: can't open file '/xxx/executeLog/alarm/20250619111721.py': [Errno 2] No such file or directory

	at xxx.service.impl.AlarmServiceImpl.outputShell(AlarmServiceImpl.java:845)
	at xxx.alarm.service.impl.AlarmServiceImpl.handleAction(AlarmServiceImpl.java:709)
	at xxx.service.impl.AlarmServiceImpl.anomalyAlarm(AlarmServiceImpl.java:366)
	at xxx.service.impl.AlarmServiceImpl$$FastClassBySpringCGLIB$$49853aeb.invoke()
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
	at xxx.alarm.service.impl.AlarmServiceImpl$$EnhancerBySpringCGLIB$$855a0ad6.anomalyAlarm()
	at xxx.service.impl.AnomalyServiceImpl.afterCreateAnomaly(AnomalyServiceImpl.java:322)
	at xxx.service.impl.AnomalyServiceImpl.lambda$insertAnomaly$0(AnomalyServiceImpl.java:221)
	at java.lang.Thread.run(Thread.java:748)

定位到报错位置在 Process 执行 Python 文件处:

java 复制代码
private void doScript(String scriptContent) throws Exception {
    ...
    String args = "python " + filePath + "/" + fileName;
    Process process = Runtime.getRuntime().exec(args);
    boolean execSuccess = true;
    try(BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
        String line = null;
        String errorLine = null;
        while ((line = in.readLine()) != null) {
            pythonResult.append(line);
        }
        ...
        process.waitFor();
        pythonFile.delete();
    } catch (Exception e) {
        ...
    }
}

可以初步分析:这段代码可能和业务耦合性不高,换句话说,这段代码是以工具类的方式存在于项目中

如果熟悉 Process 而言这是一个常见问题,使用搜索引擎也能够很快得到答案。同样的,对于 Junie 而言,这也是一个简单清晰的问题,错误原因是:

这段代码在Python进程完成后立即删除了脚本文件。然而,process.waitFor()只是等待进程结束,但不保证所有相关资源都已完全释放。在某些情况下,Python解释器可能仍在尝试访问该文件,导致出现"No such file or directory"错误。

直接就错误提问就会得到修复方案------将 process.waitFor() 移到文件读取 try 作用域后,并改用延迟删除:

java 复制代码
process.waitFor();

// 异步延迟删除文件
final File finalPythonFile = pythonFile;
executor.execute(() -> {
    try {
        // 延迟10秒后删除文件,确保Python解释器完全释放文件
        Thread.sleep(10000);
        if (finalPythonFile.exists()) {
            boolean deleted = finalPythonFile.delete();
            if (!deleted) {
                LOGGER.warn("无法删除Python脚本文件: {}", finalPythonFile.getAbsolutePath());
            }
        }
    } catch (Exception e) {
        LOGGER.error("删除Python脚本文件失败:", e);
    }
});

Junie 不仅给出了错误原因,还会自行搜索代码库,找到有类似隐患的代码

由此可见,JetBrains AI 擅长处理这种有工具属性的代码缺陷:工具属性指的是那种没有业务耦合,可以做在 Java 语言层面或是 Spring Boot 之类的开发框架上的代码。

2、Clickhouse 数据读写不一致

问题表象是业务层面问题,日志记录了按照业务现状执行到了一个不该执行的代码分支。

Clickhouse 是列式存储分布式数据库,更新数据的方式不是像 MySQL 这样的关系型数据库一样,而是更新后的数据作为一条新纪录写入,按照存储引擎做异步合并,实现更新效果。

这样就会带来一个问题,如果对修改数据实时性要求高,就没法保证修改的数据会立即查询到,因为合并是有延迟的。当然,这和 Clickhouse 的设计初衷是有悖的,为了保证查询的吞吐量会牺牲数据一致性,只能保证最终一致性。

JetBrains AI 自动摘取了代码上下文,分析到了问题根本原因:

但是,如果有业务这样使用的话,在无法做架构调整时,就要考虑备选方案。

JetBrains AI 提供了 Clickhouse 数据强制更新、延迟等待查询、重试查询等,并推荐了改动范围最小的重试查询方案。

java 复制代码
List<Map<String, Object>> alarmInfo = null;
int retryCount = 0;
int maxRetries = 5;

while (alarmInfo.isEmpty()) {
    // 查询 Clickhouse 视图
    anomalyInfos = anomalyListMapper.anomalyInfo(params);

    if (alarmInfo.isEmpty()) {
        if (retryCount >= maxRetries) {
            LOGGER.error("没有查找刚刚生成的异常数据,无法继续发送告警,xxx);
            break;
        }
        retryCount++;
        Thread.sleep(1000); // 等待1秒后重试
        LOGGER.info("尝试重新查询异常数据,重试次数:{},UUID:{}", retryCount, alarmInfo.getUuid());
    }
}

虽然这不是推荐的 Clickhouse 使用方式,但对于遗留系统维护可控成本下不失一种有效解决方案。

由此可见,虽然这是一个业务相关问题,但最终还是指向了一个基础软件的常见使用问题,JetBrains AI 也能够有效识别并解决。

3、 JetBrains AI 擅长处理的问题小结

小结一下,JetBrains AI 在代码执行层面有比较高的质量,这在线上问题解决过程中可以发挥较大作用。不仅如此,它还可以在问题分析过程中提供有效帮助,从目前验证过的场景中可以发现,在工具类问题处理、基础软件使用问题上能够做到简要快速给出指导方向。这是线上问题分析的一大利器。

如此看来,解决很多线上问题从原来问题驱动,结合问题背后的业务知识与技术储备解决问题,逐渐会转变为 AI 辅助,成体系解决问题,从全局视角发现并制定解决方案。下一节会重点介绍 Junie 如何有规划的执行任务。

相关推荐
鬼鬼鬼7 小时前
从软件1.0到3.0:在这场AI浪潮中,我们如何面对?
aigc·ai编程·cursor
散步去海边7 小时前
Cursor 进阶使用教程
前端·ai编程·cursor
摆烂工程师7 小时前
国内如何安装和使用 Claude Code 教程 - Windows 用户篇
人工智能·ai编程·claude
极客密码9 天前
Cursor再见!简单两步,Augment真无限续杯,爽用Claude 4!
ai编程·cursor·trae
栗子~~10 天前
jdk 8 、集成langchain4j,调用open-ai模型的多轮对话demo
java·开发语言·人工智能·ai编程
风生水气10 天前
关于AI Coding工具使用的一些经验分享
ai编程·cursor·vibecoding
踩着两条虫10 天前
AI + 低代码 技术揭秘(十八):集成指南
低代码·ai编程
令狐寻欢10 天前
AI 大模型应用进阶系列 ( 一 ) Python 基础
python·ai编程
鱼雀AIGC10 天前
如何仅用AI开发完整的小程序<3>—创建小程序基础框架
小程序·aigc·ai编程
loonggg10 天前
为什么AI让顶级工程师更强,却让菜鸡程序员更菜?真相扎心了
人工智能·程序员·ai编程