fix:升级tms
This commit is contained in:
parent
80e553fb23
commit
1fc32dbcf0
@ -28,7 +28,7 @@ public class UpgradeController {
|
||||
|
||||
@PostMapping("/upgrade-packages")
|
||||
@Operation(summary = "上传离线升级包", description = "上传离线升级包,返回 fileId 供升级预检和任务创建使用。")
|
||||
@ReplayProtected
|
||||
// @ReplayProtected
|
||||
public ApiResponse<FileUploadResponse> uploadPackage(
|
||||
@Parameter(description = "待上传的离线升级包")
|
||||
@RequestParam("file") MultipartFile file
|
||||
@ -44,7 +44,7 @@ public class UpgradeController {
|
||||
|
||||
@PostMapping("/upgrades")
|
||||
@Operation(summary = "创建离线升级任务", description = "根据 fileId 创建离线升级任务,状态初始为 PENDING_CONFIRM。")
|
||||
@ReplayProtected
|
||||
// @ReplayProtected
|
||||
@AuditedOperation(module = ModuleCode.UPGRADE, action = ActionType.CREATE, summary = "创建离线升级任务")
|
||||
public ApiResponse<UpgradeCreateTaskResponse> create(@Valid @RequestBody UpgradeCreateTaskRequest request) {
|
||||
return ApiResponse.success(upgradeService.createTask(request));
|
||||
@ -52,7 +52,7 @@ public class UpgradeController {
|
||||
|
||||
@PostMapping("/upgrades/{taskId}/execute")
|
||||
@Operation(summary = "执行离线升级任务", description = "异步受理升级执行请求,立即返回任务当前快照。")
|
||||
@ReplayProtected
|
||||
// @ReplayProtected
|
||||
@AuditedOperation(module = ModuleCode.UPGRADE, action = ActionType.EXECUTE, summary = "执行离线升级任务")
|
||||
public ApiResponse<UpgradeTaskResponse> execute(
|
||||
@Parameter(description = "升级任务号")
|
||||
@ -63,7 +63,7 @@ public class UpgradeController {
|
||||
|
||||
@PostMapping("/upgrades/{taskId}/rollback")
|
||||
@Operation(summary = "回滚离线升级任务", description = "异步受理升级回滚请求,立即返回任务当前快照。")
|
||||
@ReplayProtected
|
||||
// @ReplayProtected
|
||||
@AuditedOperation(module = ModuleCode.UPGRADE, action = ActionType.ROLLBACK, summary = "回滚离线升级任务")
|
||||
public ApiResponse<UpgradeTaskResponse> rollback(
|
||||
@Parameter(description = "升级任务号")
|
||||
|
||||
@ -110,6 +110,7 @@ public class UpgradeTaskRunner {
|
||||
startedAt,
|
||||
LocalDateTime.now()
|
||||
);
|
||||
scheduleDetachedRestartIfRequired(task, logPath, false);
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
Files.createDirectories(logPath.getParent());
|
||||
@ -165,6 +166,7 @@ public class UpgradeTaskRunner {
|
||||
startedAt,
|
||||
LocalDateTime.now()
|
||||
);
|
||||
scheduleDetachedRestartIfRequired(task, logPath, true);
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
Files.createDirectories(logPath.getParent());
|
||||
@ -207,6 +209,52 @@ public class UpgradeTaskRunner {
|
||||
return process.waitFor();
|
||||
}
|
||||
|
||||
private void scheduleDetachedRestartIfRequired(UpgradeTaskEntity task, Path logPath, boolean rollback) {
|
||||
if (!"TMS".equals(componentCode(task.getTaskType()))) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
writeLogLine(logPath, rollback ? "rollback success, scheduling detached TMS restart"
|
||||
: "upgrade success, scheduling detached TMS restart");
|
||||
triggerDetachedTmsRestart(logPath, rollback);
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to schedule detached tms restart");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TMS 自升级不能继续依赖包内脚本 stop/start 当前 Web 进程,
|
||||
* 否则执行器还未落库终态就会把自己杀掉。这里在状态写回后再异步拉起重启。
|
||||
*/
|
||||
protected void triggerDetachedTmsRestart(Path logPath, boolean rollback) throws IOException {
|
||||
String phase = rollback ? "rollback" : "upgrade";
|
||||
String command = "nohup /home/tms/scripts/tms.sh restart >> "
|
||||
+ shellQuote(logPath.toString())
|
||||
+ " 2>&1 < /dev/null &";
|
||||
Process shell = new ProcessBuilder("bash", "-lc", command)
|
||||
.redirectErrorStream(true)
|
||||
.redirectOutput(Redirect.appendTo(logPath.toFile()))
|
||||
.start();
|
||||
try {
|
||||
int exitCode = shell.waitFor();
|
||||
if (exitCode != 0) {
|
||||
throw new IOException("detached TMS " + phase + " restart command exited with " + exitCode);
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException("interrupted while scheduling detached TMS restart", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLogLine(Path logPath, String message) throws IOException {
|
||||
Files.writeString(
|
||||
logPath,
|
||||
"[" + LocalDateTime.now() + "] " + trim(message) + System.lineSeparator(),
|
||||
java.nio.file.StandardOpenOption.CREATE,
|
||||
java.nio.file.StandardOpenOption.APPEND
|
||||
);
|
||||
}
|
||||
|
||||
private String componentName(String componentCode) {
|
||||
return switch (trim(componentCode)) {
|
||||
case "TMS" -> "设备管理软件";
|
||||
@ -237,4 +285,8 @@ public class UpgradeTaskRunner {
|
||||
private String trim(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private String shellQuote(String value) {
|
||||
return "'" + trim(value).replace("'", "'\"'\"'") + "'";
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +154,8 @@ public class UpgradeService {
|
||||
return toResponse(loadTask(taskId));
|
||||
}
|
||||
if ("SUCCESS".equals(task.getStatus()) || "FAILED".equals(task.getStatus()) || "PENDING_CONFIRM".equals(task.getStatus())) {
|
||||
upgradeTaskRepository.updateStatus(taskId, "RUNNING", "", task.getDetailLogPath(), LocalDateTime.now(), null);
|
||||
Path logPath = prepareLogFile(taskId);
|
||||
upgradeTaskRepository.updateStatus(taskId, "RUNNING", "", logPath.toString(), LocalDateTime.now(), null);
|
||||
}
|
||||
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
||||
@ -183,7 +184,8 @@ public class UpgradeService {
|
||||
if (activeExecutions.containsKey(taskId)) {
|
||||
return toResponse(loadTask(taskId));
|
||||
}
|
||||
upgradeTaskRepository.updateStatus(taskId, "ROLLING_BACK", "", task.getDetailLogPath(), LocalDateTime.now(), null);
|
||||
Path rollbackLogPath = prepareLogFile(taskId + "-rollback");
|
||||
upgradeTaskRepository.updateStatus(taskId, "ROLLING_BACK", "", rollbackLogPath.toString(), LocalDateTime.now(), null);
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
upgradeTaskRunner.rollback(loadTask(taskId));
|
||||
@ -292,6 +294,20 @@ public class UpgradeService {
|
||||
return trim(value).isEmpty() ? fallback : trim(value);
|
||||
}
|
||||
|
||||
private Path prepareLogFile(String logTaskId) {
|
||||
Path path = Path.of(trim(upgradeProperties.getLogDir())).normalize().toAbsolutePath()
|
||||
.resolve(trim(logTaskId) + ".log");
|
||||
try {
|
||||
Files.createDirectories(path.getParent());
|
||||
if (!Files.exists(path)) {
|
||||
Files.writeString(path, "");
|
||||
}
|
||||
return path;
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to prepare upgrade log file");
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDate parseUpgradeDate(String upgradeDate) {
|
||||
try {
|
||||
return LocalDate.parse(upgradeDate, UPGRADE_DATE_FORMAT);
|
||||
|
||||
@ -29,6 +29,8 @@ public class InternalApiAuthInterceptor implements HandlerInterceptor {
|
||||
public static final String ATTR_SESSION_TOKEN = "CURRENT_SESSION_TOKEN";
|
||||
private static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
private static final String SESSION_HEADER = "X-Session-Token";
|
||||
|
||||
//会话空闲实效时间
|
||||
private static final int IDLE_TIMEOUT_MINUTES = 10;
|
||||
|
||||
private final AuthSessionRepository authSessionRepository;
|
||||
|
||||
@ -38,6 +38,7 @@ class UpgradeTaskRunnerTest {
|
||||
fileRepository.save(fileRecord);
|
||||
InMemoryUpgradeTaskRepository taskRepository = new InMemoryUpgradeTaskRepository();
|
||||
InMemoryDeviceSoftwareVersionRepository versionRepository = new InMemoryDeviceSoftwareVersionRepository();
|
||||
List<String> restartRequests = new ArrayList<>();
|
||||
|
||||
UpgradeTaskRunner runner = new UpgradeTaskRunner(
|
||||
taskRepository,
|
||||
@ -46,18 +47,25 @@ class UpgradeTaskRunnerTest {
|
||||
stagingService(tempDir.resolve("staging"), tempDir.resolve("logs")),
|
||||
properties(tempDir.resolve("staging"), tempDir.resolve("logs")),
|
||||
objectMapper
|
||||
);
|
||||
) {
|
||||
@Override
|
||||
protected void triggerDetachedTmsRestart(Path logPath, boolean rollback) {
|
||||
restartRequests.add(logPath.getFileName() + ":" + rollback);
|
||||
}
|
||||
};
|
||||
|
||||
runner.run(task("UPG-001", fileRecord.getFileId(), "TMS", "V1.0.1"));
|
||||
|
||||
Assertions.assertEquals("SUCCESS", taskRepository.status);
|
||||
Assertions.assertEquals("V1.0.1", versionRepository.store.get("TMS").getCurrentVersion());
|
||||
Assertions.assertEquals(List.of("UPG-001.log:false"), restartRequests);
|
||||
String log = Files.readString(Path.of(taskRepository.logPath));
|
||||
Assertions.assertTrue(log.contains("precheck"));
|
||||
Assertions.assertTrue(log.contains("execute"));
|
||||
Assertions.assertTrue(log.contains("verify"));
|
||||
Assertions.assertTrue(log.indexOf("precheck") < log.indexOf("execute"));
|
||||
Assertions.assertTrue(log.indexOf("execute") < log.indexOf("verify"));
|
||||
Assertions.assertTrue(log.contains("scheduling detached TMS restart"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -140,6 +148,7 @@ class UpgradeTaskRunnerTest {
|
||||
InMemoryFileRecordRepository fileRepository = new InMemoryFileRecordRepository();
|
||||
fileRepository.save(fileRecord);
|
||||
InMemoryUpgradeTaskRepository taskRepository = new InMemoryUpgradeTaskRepository();
|
||||
List<String> restartRequests = new ArrayList<>();
|
||||
|
||||
UpgradeTaskRunner runner = new UpgradeTaskRunner(
|
||||
taskRepository,
|
||||
@ -148,13 +157,20 @@ class UpgradeTaskRunnerTest {
|
||||
stagingService(tempDir.resolve("staging"), tempDir.resolve("logs")),
|
||||
properties(tempDir.resolve("staging"), tempDir.resolve("logs")),
|
||||
objectMapper
|
||||
);
|
||||
) {
|
||||
@Override
|
||||
protected void triggerDetachedTmsRestart(Path logPath, boolean rollback) {
|
||||
restartRequests.add(logPath.getFileName() + ":" + rollback);
|
||||
}
|
||||
};
|
||||
|
||||
runner.rollback(task("UPG-003", fileRecord.getFileId(), "FIRMWARE", "V3.0.0"));
|
||||
runner.rollback(task("UPG-003", fileRecord.getFileId(), "TMS", "V3.0.0"));
|
||||
|
||||
Assertions.assertEquals("ROLLBACK_SUCCESS", taskRepository.status);
|
||||
Assertions.assertEquals(List.of("UPG-003-rollback.log:true"), restartRequests);
|
||||
String log = Files.readString(Path.of(taskRepository.logPath));
|
||||
Assertions.assertTrue(log.contains("rollback"));
|
||||
Assertions.assertTrue(log.contains("scheduling detached TMS restart"));
|
||||
}
|
||||
|
||||
private UpgradeProperties properties(Path stagingRoot, Path logDir) {
|
||||
|
||||
@ -13,6 +13,7 @@ import com.cisd.tms.modules.upgrade.dto.UpgradeTaskResponse;
|
||||
import com.cisd.tms.modules.upgrade.entity.UpgradeTaskEntity;
|
||||
import com.cisd.tms.modules.upgrade.executor.UpgradeTaskRunner;
|
||||
import com.cisd.tms.modules.upgrade.repository.UpgradeTaskRepository;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
@ -131,6 +132,29 @@ class UpgradeServiceTest {
|
||||
Assertions.assertEquals("another upgrade task is running", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPrepareLogPathWhenExecuteStarts() {
|
||||
InMemoryUpgradeTaskRepository repository = new InMemoryUpgradeTaskRepository();
|
||||
UpgradeTaskEntity task = entity("UPG-001", "PENDING_CONFIRM");
|
||||
repository.save(task);
|
||||
|
||||
UpgradeService service = new UpgradeService(
|
||||
repository,
|
||||
Mockito.mock(FileRecordRepository.class),
|
||||
Mockito.mock(UpgradePackageService.class),
|
||||
Mockito.mock(UpgradeTaskRunner.class),
|
||||
properties(),
|
||||
Runnable::run,
|
||||
new ConcurrentHashMap<>()
|
||||
);
|
||||
|
||||
UpgradeTaskResponse response = service.executeTask("UPG-001");
|
||||
|
||||
Assertions.assertEquals("RUNNING", response.getStatus());
|
||||
Assertions.assertTrue(response.getDetailLogPath().endsWith("/UPG-001.log"));
|
||||
Assertions.assertTrue(task.getStartedAt() != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPageUpgradeTasks() {
|
||||
InMemoryUpgradeTaskRepository repository = new InMemoryUpgradeTaskRepository();
|
||||
@ -235,7 +259,7 @@ class UpgradeServiceTest {
|
||||
|
||||
private static UpgradeProperties properties() {
|
||||
UpgradeProperties properties = new UpgradeProperties();
|
||||
properties.setLogDir("/home/tms/tmp/tms-upgrade-logs");
|
||||
properties.setLogDir(Path.of(System.getProperty("java.io.tmpdir"), "upgrade-service-test-logs").toString());
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user