fix(snapshot): 修复备份进行中被删除导致容器崩溃的问题
1. checkDone 中 statSync 加 try-catch,文件被删时 reject 而非 uncaught crash 2. 删除 API 禁止删除 RUNNING 状态的任务,返回 409 Conflict 3. compose 补充 restart: unless-stopped,防止异常退出后服务不可用 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
18675f083c
commit
27db2a5aa2
|
|
@ -14,6 +14,7 @@ services:
|
||||||
context: ./snapshot-service
|
context: ./snapshot-service
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: rwa-snapshot-service-2
|
container_name: rwa-snapshot-service-2
|
||||||
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "3199:3199"
|
- "3199:3199"
|
||||||
environment:
|
environment:
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,11 @@ export class SnapshotController {
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
@ApiOperation({ summary: '删除备份' })
|
@ApiOperation({ summary: '删除备份' })
|
||||||
async deleteSnapshot(@Param('id') id: string) {
|
async deleteSnapshot(@Param('id') id: string) {
|
||||||
|
const task = await this.repo.findById(id);
|
||||||
|
if (!task) throw new NotFoundException('备份任务不存在');
|
||||||
|
if (task.status === 'RUNNING') {
|
||||||
|
throw new ConflictException('备份任务正在执行中,无法删除,请等待完成后再操作');
|
||||||
|
}
|
||||||
await this.orchestrator.deleteSnapshot(id);
|
await this.orchestrator.deleteSnapshot(id);
|
||||||
return { message: '备份已删除' };
|
return { message: '备份已删除' };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,10 @@ export class SnapshotOrchestratorService implements OnModuleInit {
|
||||||
const task = await this.repo.findById(taskId);
|
const task = await this.repo.findById(taskId);
|
||||||
if (!task) throw new Error(`任务不存在: ${taskId}`);
|
if (!task) throw new Error(`任务不存在: ${taskId}`);
|
||||||
|
|
||||||
|
if (task.status === SnapshotStatus.RUNNING) {
|
||||||
|
throw new Error('备份任务正在执行中,无法删除,请等待完成后再操作');
|
||||||
|
}
|
||||||
|
|
||||||
if (task.storageType === StorageType.LOCAL) {
|
if (task.storageType === StorageType.LOCAL) {
|
||||||
this.localStorage.deleteTask(taskId);
|
this.localStorage.deleteTask(taskId);
|
||||||
} else if (task.storageType === StorageType.MINIO) {
|
} else if (task.storageType === StorageType.MINIO) {
|
||||||
|
|
|
||||||
|
|
@ -119,10 +119,16 @@ export class PostgresBackupHandler implements BackupHandler {
|
||||||
if (dumpExitCode === null || gzipExitCode === null) return;
|
if (dumpExitCode === null || gzipExitCode === null) return;
|
||||||
|
|
||||||
if (dumpExitCode === 0 && gzipExitCode === 0) {
|
if (dumpExitCode === 0 && gzipExitCode === 0) {
|
||||||
const stat = fs.statSync(filePath);
|
try {
|
||||||
this.logger.log(`PostgreSQL 备份完成: ${fileName}, 压缩后: ${stat.size} bytes, 原始输出: ${bytesRead} bytes`);
|
const stat = fs.statSync(filePath);
|
||||||
onProgress(100, 'PostgreSQL 备份完成');
|
this.logger.log(`PostgreSQL 备份完成: ${fileName}, 压缩后: ${stat.size} bytes, 原始输出: ${bytesRead} bytes`);
|
||||||
resolve({ fileName, filePath, fileSize: stat.size });
|
onProgress(100, 'PostgreSQL 备份完成');
|
||||||
|
resolve({ fileName, filePath, fileSize: stat.size });
|
||||||
|
} catch (err) {
|
||||||
|
const msg = `备份文件不可访问 (可能已被删除): ${filePath}`;
|
||||||
|
this.logger.error(msg);
|
||||||
|
reject(new Error(msg));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const error = `pg_dumpall 退出码: ${dumpExitCode}, gzip 退出码: ${gzipExitCode}, stderr: ${stderrBuffer.slice(-500)}`;
|
const error = `pg_dumpall 退出码: ${dumpExitCode}, gzip 退出码: ${gzipExitCode}, stderr: ${stderrBuffer.slice(-500)}`;
|
||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue