{"record":{"id":"33ace11f78c5ccbd","repo":"elunez/eladmin","slug":"appname","errorCode":null,"errorMessage":"应用信息不存在：{appName}","messagePattern":"应用信息不存在：(.+?)","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DeployServiceImpl.java","lineNumber":351,"sourceCode":"\t\t\t} else {\n\t\t\t\tsb.append(\"<br>关闭成功!\");\n\t\t\t\tsendMsg(sb.toString(), MsgType.INFO);\n\t\t\t}\n\t\t\tlog.info(sb.toString());\n\t\t\texecuteShellUtil.close();\n\t\t}\n\t\treturn \"执行完毕\";\n\t}\n\n\t@Override\n\tpublic String serverReduction(DeployHistory resources) {\n\t\tLong deployId = resources.getDeployId();\n\t\tDeploy deployInfo = deployRepository.findById(deployId).orElseGet(Deploy::new);\n\t\tString deployDate = DateUtil.format(resources.getDeployDate(), DatePattern.PURE_DATETIME_PATTERN);\n\t\tApp app = deployInfo.getApp();\n\t\tif (app == null) {\n\t\t\tsendMsg(\"应用信息不存在：\" + resources.getAppName(), MsgType.ERROR);\n\t\t\tthrow new BadRequestException(\"应用信息不存在：\" + resources.getAppName());\n\t\t}\n\t\tString backupPath = app.getBackupPath()+FILE_SEPARATOR;\n\t\tbackupPath += resources.getAppName() + FILE_SEPARATOR + deployDate;\n\t\t//这个是服务器部署路径\n\t\tString deployPath = app.getDeployPath();\n\t\tString ip = resources.getIp();\n\t\tExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip);\n\t\tString msg;\n\n\t\tmsg = String.format(\"登陆到服务器:%s\", ip);\n\t\tlog.info(msg);\n\t\tsendMsg(msg, MsgType.INFO);\n\t\tsendMsg(\"停止原来应用\", MsgType.INFO);\n\t\t//停止应用\n\t\tstopApp(app.getPort(), executeShellUtil);\n\t\t//删除原来应用\n\t\tsendMsg(\"删除应用\", MsgType.INFO);\n\t\texecuteShellUtil.execute(\"rm -rf \" + deployPath + FILE_SEPARATOR + resources.getAppName());","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/elunez/eladmin/blob/55fbf705956949697dbd68bf9003776609d3d029/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DeployServiceImpl.java#L333-L369","documentation":"DeployServiceImpl.serverReduction (rollback) loads the Deploy for resources.getDeployId(); if that Deploy has no App it sends '应用信息不存在：<appName>' over WebSocket and throws BadRequestException with the same text. Rollback needs the App's backupPath/deployPath to locate the timestamped backup on the target server, so a missing App aborts the operation.","triggerScenarios":"POST /api/deploy/serverReduction with a DeployHistory whose deployId points to a Deploy row with null/dangling app_id. Common when rolling back old history entries after the linked App was deleted.","commonSituations":"App deleted but its DeployHistory retained; deploy history restored from a backup into a schema where app rows are gone; manually edited history records with wrong deployId.","solutions":["Recreate or re-link the App for the referenced Deploy (set mnt_deploy.app_id), then retry the rollback.","If the App is permanently gone, remove the orphan DeployHistory entries — rollback is impossible without the App's path configuration.","Before rolling back, verify GET /api/deploy/<deployId> returns a record with a non-null app."],"exampleFix":"// before: rollback an orphan history\ndeployService.serverReduction(history); // deployInfo.getApp() == null -> 应用信息不存在\n\n// after: verify first\nDeploy d = deployRepository.findById(history.getDeployId()).orElse(null);\nif (d == null || d.getApp() == null) { /* fix data or abort with clear message */ }\ndeployService.serverReduction(history);","handlingStrategy":"validation","validationCode":"// Before rollback, verify the history's deploy still resolves to an App\nDeploy deployInfo = deployRepository.findById(history.getDeployId()).orElse(null);\nif (deployInfo == null || deployInfo.getApp() == null) {\n    throw new IllegalStateException(\"应用信息不存在：\" + history.getAppName() + \" — 无法回滚\");\n}\ndeployService.serverReduction(history);","typeGuard":"boolean isRollbackable(DeployRepository repo, DeployHistory h) {\n    return h.getDeployId() != null\n        && repo.findById(h.getDeployId()).map(d -> d.getApp() != null).orElse(false);\n}","tryCatchPattern":"try {\n    deployService.serverReduction(history);\n} catch (BadRequestException e) {\n    if (e.getMessage().contains(\"应用信息不存在\")) { notifyOpsOrphanHistory(history.getDeployId()); return; }\n    throw e;\n}","preventionTips":["Block App deletion while Deploy/DeployHistory rows reference it, or cascade them.","When restoring databases, restore mnt_app together with mnt_deploy/mnt_deploy_history to keep links intact.","Validate deployId + app presence in the rollback UI before enabling the rollback button."],"tags":["deployment","rollback","data-integrity","eladmin","maintenance"],"backgroundTag":null,"analyzedSha":"55fbf705956949697dbd68bf9003776609d3d029","analyzedAt":"2026-08-14T11:56:12.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}