我有一个调用服务的 spring 控制器,它使用命令行使用 7zip 进行压缩或解压缩(这是外部要求,必须是来自命令行的 7zip)
这里有一个简化的方法:
public File zipDirInPlace(File backupDir, int timeoutTime, TimeUnit timeUnit) throws IOException, InterruptedException {
log.info("Zipping Folder {}", backupDir.getAbsolutePath());
File zipDir = new File(backupDir.getPath() + ".zip");
String[] command = { sevenZip, "a", zipDir.getAbsolutePath(), backupDir.getAbsolutePath() + "\\*" };
// Create a process builder
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true);
// Start the process
Process process = processBuilder.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
log.info("7Zip claims: {}", line);
}
} catch (IOException e) {
log.error("Error reading process output", e);
}
// Wait for the process to complete
try {
if (!process.waitFor(timeoutTime, timeUnit)) {
// If time has passed, kill it.
process.destroy();
// If it is not killed in 1 minute again with more force.
process.waitFor(1, TimeUnit.MINUTES);
process.destroyForcibly();
}
} catch (InterruptedException e) {
log.error("Running 7zip was interrupted", e);
// Thread.currentThread().interrupt(); ??
throw new InterruptedException(e);
}
int exitCode = process.exitValue();
// Check the exit code
if (exitCode == 0) {
log.info("Packing completed successfully");
} else {
log.error("Could not zip {}", exitCode);
}
return zipDir;
}
预期的行为是这样的: 打包 zip,如果该过程花费的时间超过 10 分钟,则终止它。 一旦进程被终止,控制器就会获取 InterruptedException 并返回自定义错误响应:
catch (InterruptedException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Something went wrong using 7zip from command line", e);
}
问题: Sonar 抱怨控制器确实消耗了异常,而没有重新抛出它或中断线程。 然而: a) 重新抛出它没有意义,因为控制器将不会返回自定义 http 消息。 b)中断线程,该线程可能是控制器线程,也可能是服务线程,具体取决于它发生的位置以及 spring 内部的工作方式,这似乎不是一个明智的举动。 (参见中断Sping线程)
如何正确处理异常? 我在理解 Thread.currentThread().interrupt(); 时有错误吗?是吗?
要满足声纳,只需添加删除控制器中的
catch
,然后在控制器中写入@ExceptionHandler
。
@ExceptionHandler(InterruptedException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Something went wrong using 7zip from command line")
public void handleInterrupt() {}
这应该产生相同的最终结果,但满足 Sonar,因为您现在删除了
catch
子句,您也可以在服务中删除它。