diff --git a/agent/app/dto/backup.go b/agent/app/dto/backup.go index 31aa9e021..1a069134a 100644 --- a/agent/app/dto/backup.go +++ b/agent/app/dto/backup.go @@ -99,6 +99,9 @@ type BackupRecords struct { DownloadAccountID uint `json:"downloadAccountID"` FileDir string `json:"fileDir"` FileName string `json:"fileName"` + TaskID string `json:"taskID"` + Status string `json:"status"` + Message string `json:"message"` Description string `json:"description"` } diff --git a/agent/app/model/backup.go b/agent/app/model/backup.go index ad69b46c3..392bd7e21 100644 --- a/agent/app/model/backup.go +++ b/agent/app/model/backup.go @@ -27,5 +27,8 @@ type BackupRecord struct { FileDir string `json:"fileDir"` FileName string `json:"fileName"` + TaskID string `json:"taskID"` + Status string `json:"status"` + Message string `json:"message"` Description string `json:"description"` } diff --git a/agent/app/service/backup_app.go b/agent/app/service/backup_app.go index 976c3f0d6..e38d368e5 100644 --- a/agent/app/service/backup_app.go +++ b/agent/app/service/backup_app.go @@ -45,35 +45,28 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, er fileName = fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow+common.RandStrAndNum(5)) } - backupApp := func() (*model.BackupRecord, error) { - if err = handleAppBackup(&install, nil, backupDir, fileName, "", req.Secret, req.TaskID); err != nil { - global.LOG.Errorf("backup app %s failed, err: %v", req.DetailName, err) - return nil, err - } - record := &model.BackupRecord{ - Type: "app", - Name: req.Name, - DetailName: req.DetailName, - SourceAccountIDs: "1", - DownloadAccountID: 1, - FileDir: itemDir, - FileName: fileName, - Description: req.Description, - } - if err := backupRepo.CreateRecord(record); err != nil { - global.LOG.Errorf("save backup record failed, err: %v", err) - return nil, err - } - return record, nil + record := &model.BackupRecord{ + Type: "app", + Name: req.Name, + DetailName: req.DetailName, + SourceAccountIDs: "1", + DownloadAccountID: 1, + FileDir: itemDir, + FileName: fileName, + TaskID: req.TaskID, + Status: constant.StatusWaiting, + Description: req.Description, + } + if err := backupRepo.CreateRecord(record); err != nil { + global.LOG.Errorf("save backup record failed, err: %v", err) + return nil, err } - if req.TaskID != "" { - go func() { - _, _ = backupApp() - }() - } else { - return backupApp() + if err = handleAppBackup(&install, nil, record.ID, backupDir, fileName, "", req.Secret, req.TaskID); err != nil { + global.LOG.Errorf("backup app %s failed, err: %v", req.DetailName, err) + return nil, err } + return nil, nil } @@ -94,11 +87,9 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error { if _, err := compose.Down(install.GetComposePath()); err != nil { return err } - go func() { - if err := handleAppRecover(&install, nil, req.File, false, req.Secret, req.TaskID); err != nil { - global.LOG.Errorf("recover app %s failed, err: %v", req.DetailName, err) - } - }() + if err := handleAppRecover(&install, nil, req.File, false, req.Secret, req.TaskID); err != nil { + global.LOG.Errorf("recover app %s failed, err: %v", req.DetailName, err) + } return nil } @@ -111,7 +102,7 @@ func backupDatabaseWithTask(parentTask *task.Task, resourceKey, tmpDir, name str } parentTask.LogStart(task.GetTaskName(db.Name, task.TaskBackup, task.TaskScopeDatabase)) databaseHelper := DatabaseHelper{Database: db.MysqlName, DBType: resourceKey, Name: db.Name} - if err := handleMysqlBackup(databaseHelper, parentTask, tmpDir, fmt.Sprintf("%s.sql.gz", name), ""); err != nil { + if err := handleMysqlBackup(databaseHelper, parentTask, 0, tmpDir, fmt.Sprintf("%s.sql.gz", name), ""); err != nil { return err } parentTask.LogSuccess(task.GetTaskName(db.Name, task.TaskBackup, task.TaskScopeDatabase)) @@ -122,7 +113,7 @@ func backupDatabaseWithTask(parentTask *task.Task, resourceKey, tmpDir, name str } parentTask.LogStart(task.GetTaskName(db.Name, task.TaskBackup, task.TaskScopeDatabase)) databaseHelper := DatabaseHelper{Database: db.PostgresqlName, DBType: resourceKey, Name: db.Name} - if err := handlePostgresqlBackup(databaseHelper, parentTask, tmpDir, fmt.Sprintf("%s.sql.gz", name), ""); err != nil { + if err := handlePostgresqlBackup(databaseHelper, parentTask, 0, tmpDir, fmt.Sprintf("%s.sql.gz", name), ""); err != nil { return err } parentTask.LogSuccess(task.GetTaskName(db.Name, task.TaskBackup, task.TaskScopeDatabase)) @@ -130,7 +121,7 @@ func backupDatabaseWithTask(parentTask *task.Task, resourceKey, tmpDir, name str return nil } -func handleAppBackup(install *model.AppInstall, parentTask *task.Task, backupDir, fileName, excludes, secret, taskID string) error { +func handleAppBackup(install *model.AppInstall, parentTask *task.Task, recordID uint, backupDir, fileName, excludes, secret, taskID string) error { var ( err error backupTask *task.Task @@ -144,11 +135,20 @@ func handleAppBackup(install *model.AppInstall, parentTask *task.Task, backupDir } itemHandler := func() error { return doAppBackup(install, backupTask, backupDir, fileName, excludes, secret) } - backupTask.AddSubTask(task.GetTaskName(install.Name, task.TaskBackup, task.TaskScopeApp), func(t *task.Task) error { return itemHandler() }, nil) if parentTask != nil { return itemHandler() } - return backupTask.Execute() + + backupTask.AddSubTaskWithOps(task.GetTaskName(install.Name, task.TaskBackup, task.TaskScopeApp), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour) + go func() { + if err := backupTask.Execute(); err != nil { + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + return + } + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess}) + }() + + return nil } func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverFile string, isRollback bool, secret, taskID string) error { @@ -170,7 +170,7 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF fileOp := files.NewFileOp() if !isRollback { rollbackFile = path.Join(global.Dir.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format(constant.DateTimeSlimLayout))) - if err := handleAppBackup(install, recoverTask, path.Dir(rollbackFile), path.Base(rollbackFile), "", "", taskID); err != nil { + if err := handleAppBackup(install, recoverTask, 0, path.Dir(rollbackFile), path.Base(rollbackFile), "", "", taskID); err != nil { t.Log(fmt.Sprintf("backup app %s for rollback before recover failed, err: %v", install.Name, err)) } } @@ -324,12 +324,15 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF _ = os.RemoveAll(rollbackFile) } } - - recoverTask.AddSubTask(task.GetTaskName(install.Name, task.TaskRecover, task.TaskScopeApp), recoverApp, rollBackApp) if parentTask != nil { return recoverApp(parentTask) } - return recoverTask.Execute() + + recoverTask.AddSubTask(task.GetTaskName(install.Name, task.TaskRecover, task.TaskScopeApp), recoverApp, rollBackApp) + go func() { + _ = recoverTask.Execute() + }() + return nil } func doAppBackup(install *model.AppInstall, parentTask *task.Task, backupDir, fileName, excludes, secret string) error { diff --git a/agent/app/service/backup_mysql.go b/agent/app/service/backup_mysql.go index df4ba8a34..ba75ac21d 100644 --- a/agent/app/service/backup_mysql.go +++ b/agent/app/service/backup_mysql.go @@ -30,11 +30,6 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error { targetDir := path.Join(global.Dir.LocalBackupDir, itemDir) fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5)) - databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName} - if err := handleMysqlBackup(databaseHelper, nil, targetDir, fileName, req.TaskID); err != nil { - return err - } - record := &model.BackupRecord{ Type: req.Type, Name: req.Name, @@ -43,19 +38,25 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error { DownloadAccountID: 1, FileDir: itemDir, FileName: fileName, + TaskID: req.TaskID, + Status: constant.StatusWaiting, Description: req.Description, } if err := backupRepo.CreateRecord(record); err != nil { global.LOG.Errorf("save backup record failed, err: %v", err) + return err + } + + databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName} + if err := handleMysqlBackup(databaseHelper, nil, record.ID, targetDir, fileName, req.TaskID); err != nil { + backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + return err } return nil } func (u *BackupService) MysqlRecover(req dto.CommonRecover) error { - if err := handleMysqlRecover(req, nil, false, req.TaskID); err != nil { - return err - } - return nil + return handleMysqlRecover(req, nil, false, req.TaskID) } func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error { @@ -64,14 +65,14 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error { return err } req.File = recoveFile + if err := handleMysqlRecover(req, nil, false, req.TaskID); err != nil { return err } - global.LOG.Info("recover from uploads successful!") return nil } -func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir, fileName, taskID string) error { +func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, recordID uint, targetDir, fileName, taskID string) error { var ( err error backupTask *task.Task @@ -90,11 +91,18 @@ func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir, file } itemHandler := func() error { return doMysqlBackup(db, targetDir, fileName) } - backupTask.AddSubTask(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeDatabase), func(t *task.Task) error { return itemHandler() }, nil) if parentTask != nil { return itemHandler() } - return backupTask.Execute() + backupTask.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeDatabase), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour) + go func() { + if err := backupTask.Execute(); err != nil { + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + return + } + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess}) + }() + return nil } func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback bool, taskID string) error { @@ -139,8 +147,6 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback Format: dbInfo.Format, TargetDir: path.Dir(rollbackFile), FileName: path.Base(rollbackFile), - - Timeout: 300, }); err != nil { return fmt.Errorf("backup mysql db %s for rollback before recover failed, err: %v", req.DetailName, err) } @@ -153,8 +159,6 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback Version: version, Format: dbInfo.Format, SourceFile: rollbackFile, - - Timeout: 300, }); err != nil { global.LOG.Errorf("rollback mysql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err) } else { @@ -172,8 +176,6 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback Version: version, Format: dbInfo.Format, SourceFile: req.File, - - Timeout: 300, }); err != nil { global.LOG.Errorf("recover mysql db %s from %s failed, err: %v", req.DetailName, req.File, err) return err @@ -181,12 +183,15 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback isOk = true return nil } - itemTask.AddSubTask(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil) if parentTask != nil { return recoverDatabase(parentTask) } - return itemTask.Execute() + itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 3, time.Hour) + go func() { + _ = itemTask.Execute() + }() + return nil } func doMysqlBackup(db DatabaseHelper, targetDir, fileName string) error { @@ -205,8 +210,6 @@ func doMysqlBackup(db DatabaseHelper, targetDir, fileName string) error { Format: dbInfo.Format, TargetDir: targetDir, FileName: fileName, - - Timeout: 300, } return cli.Backup(backupInfo) } diff --git a/agent/app/service/backup_postgresql.go b/agent/app/service/backup_postgresql.go index d383408b8..8a21fb690 100644 --- a/agent/app/service/backup_postgresql.go +++ b/agent/app/service/backup_postgresql.go @@ -29,11 +29,6 @@ func (u *BackupService) PostgresqlBackup(req dto.CommonBackup) error { targetDir := path.Join(global.Dir.LocalBackupDir, itemDir) fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5)) - databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName} - if err := handlePostgresqlBackup(databaseHelper, nil, targetDir, fileName, req.TaskID); err != nil { - return err - } - record := &model.BackupRecord{ Type: req.Type, Name: req.Name, @@ -42,11 +37,18 @@ func (u *BackupService) PostgresqlBackup(req dto.CommonBackup) error { DownloadAccountID: 1, FileDir: itemDir, FileName: fileName, + TaskID: req.TaskID, + Status: constant.StatusWaiting, Description: req.Description, } if err := backupRepo.CreateRecord(record); err != nil { global.LOG.Errorf("save backup record failed, err: %v", err) } + + databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName} + if err := handlePostgresqlBackup(databaseHelper, nil, record.ID, targetDir, fileName, req.TaskID); err != nil { + return err + } return nil } func (u *BackupService) PostgresqlRecover(req dto.CommonRecover) error { @@ -69,7 +71,7 @@ func (u *BackupService) PostgresqlRecoverByUpload(req dto.CommonRecover) error { return nil } -func handlePostgresqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir, fileName, taskID string) error { +func handlePostgresqlBackup(db DatabaseHelper, parentTask *task.Task, recordID uint, targetDir, fileName, taskID string) error { var ( err error backupTask *task.Task @@ -84,11 +86,18 @@ func handlePostgresqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir, } itemHandler := func() error { return doPostgresqlgBackup(db, targetDir, fileName) } - backupTask.AddSubTask(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeDatabase), func(task *task.Task) error { return itemHandler() }, nil) if parentTask != nil { return itemHandler() } - return backupTask.Execute() + backupTask.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeDatabase), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour) + go func() { + if err := backupTask.Execute(); err != nil { + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + return + } + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess}) + }() + return nil } func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback bool) error { @@ -163,12 +172,15 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol isOk = true return nil } - itemTask.AddSubTask(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil) if parentTask != nil { return recoverDatabase(parentTask) } - return itemTask.Execute() + itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 3, time.Hour) + go func() { + _ = itemTask.Execute() + }() + return nil } func doPostgresqlgBackup(db DatabaseHelper, targetDir, fileName string) error { diff --git a/agent/app/service/backup_record.go b/agent/app/service/backup_record.go index 2d7a590eb..28baee440 100644 --- a/agent/app/service/backup_record.go +++ b/agent/app/service/backup_record.go @@ -11,6 +11,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/app/repo" + "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/jinzhu/copier" ) @@ -239,6 +240,9 @@ func (u *BackupRecordService) LoadRecordSize(req dto.SearchForSize) ([]dto.Recor return nil, err } for _, item := range records { + if item.Status == constant.StatusWaiting { + continue + } list = append(list, backupSizeHelper{ID: item.ID, DownloadID: item.DownloadAccountID, FilePath: path.Join(item.FileDir, item.FileName)}) } } diff --git a/agent/app/service/backup_redis.go b/agent/app/service/backup_redis.go index 441f2aa5e..4deabac41 100644 --- a/agent/app/service/backup_redis.go +++ b/agent/app/service/backup_redis.go @@ -44,22 +44,24 @@ func (u *BackupService) RedisBackup(req dto.CommonBackup) error { } itemDir := fmt.Sprintf("database/redis/%s", redisInfo.Name) backupDir := path.Join(global.Dir.LocalBackupDir, itemDir) - if err := handleRedisBackup(redisInfo, nil, backupDir, fileName, req.Secret, req.TaskID); err != nil { - return err - } record := &model.BackupRecord{ - Type: "redis", + Type: req.Type, Name: req.Name, SourceAccountIDs: "1", DownloadAccountID: 1, FileDir: itemDir, FileName: fileName, + TaskID: req.TaskID, + Status: constant.StatusWaiting, Description: req.Description, } if err := backupRepo.CreateRecord(record); err != nil { global.LOG.Errorf("save backup record failed, err: %v", err) } + if err := handleRedisBackup(redisInfo, nil, record.ID, backupDir, fileName, req.Secret, req.TaskID); err != nil { + return err + } return nil } @@ -75,8 +77,7 @@ func (u *BackupService) RedisRecover(req dto.CommonRecover) error { return nil } -func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDir, fileName, secret, taskID string) error { - +func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, recordID uint, backupDir, fileName, secret, taskID string) error { var ( err error itemTask *task.Task @@ -128,6 +129,14 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDi return backupDatabase(parentTask) } + itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskBackup"), backupDatabase, nil, 3, time.Hour) + go func() { + if err := itemTask.Execute(); err != nil { + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + return + } + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess}) + }() return itemTask.Execute() } @@ -180,7 +189,7 @@ func handleRedisRecover(redisInfo *repo.RootInfo, parentTask *task.Task, recover } } rollbackFile := path.Join(global.Dir.TmpDir, fmt.Sprintf("database/redis/%s_%s.%s", redisInfo.Name, time.Now().Format(constant.DateTimeSlimLayout), suffix)) - if err := handleRedisBackup(redisInfo, nil, path.Dir(rollbackFile), path.Base(rollbackFile), secret, ""); err != nil { + if err := handleRedisBackup(redisInfo, nil, 0, path.Dir(rollbackFile), path.Base(rollbackFile), secret, ""); err != nil { return fmt.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err) } defer func() { @@ -230,5 +239,8 @@ func handleRedisRecover(redisInfo *repo.RootInfo, parentTask *task.Task, recover return recoverDatabase(parentTask) } - return itemTask.Execute() + go func() { + _ = itemTask.Execute() + }() + return nil } diff --git a/agent/app/service/backup_website.go b/agent/app/service/backup_website.go index 51b617928..35f74bf69 100644 --- a/agent/app/service/backup_website.go +++ b/agent/app/service/backup_website.go @@ -38,26 +38,26 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error { backupDir := path.Join(global.Dir.LocalBackupDir, itemDir) fileName := fmt.Sprintf("%s_%s.tar.gz", website.Alias, timeNow+common.RandStrAndNum(5)) - go func() { - if err = handleWebsiteBackup(&website, nil, backupDir, fileName, "", req.Secret, req.TaskID); err != nil { - global.LOG.Errorf("backup website %s failed, err: %v", website.Alias, err) - return - } - record := &model.BackupRecord{ - Type: "website", - Name: website.Alias, - DetailName: website.Alias, - SourceAccountIDs: "1", - DownloadAccountID: 1, - FileDir: itemDir, - FileName: fileName, - Description: req.Description, - } - if err = backupRepo.CreateRecord(record); err != nil { - global.LOG.Errorf("save backup record failed, err: %v", err) - return - } - }() + record := &model.BackupRecord{ + Type: "website", + Name: website.Alias, + DetailName: website.Alias, + SourceAccountIDs: "1", + DownloadAccountID: 1, + FileDir: itemDir, + FileName: fileName, + TaskID: req.TaskID, + Status: constant.StatusWaiting, + Description: req.Description, + } + if err = backupRepo.CreateRecord(record); err != nil { + global.LOG.Errorf("save backup record failed, err: %v", err) + return err + } + if err = handleWebsiteBackup(&website, nil, record.ID, backupDir, fileName, "", req.Secret, req.TaskID); err != nil { + global.LOG.Errorf("backup website %s failed, err: %v", website.Alias, err) + return err + } return nil } @@ -66,11 +66,9 @@ func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error { if err != nil { return err } - go func() { - if err := handleWebsiteRecover(&website, req.File, false, req.Secret, req.TaskID); err != nil { - global.LOG.Errorf("recover website %s failed, err: %v", website.Alias, err) - } - }() + if err := handleWebsiteRecover(&website, req.File, false, req.Secret, req.TaskID); err != nil { + global.LOG.Errorf("recover website %s failed, err: %v", website.Alias, err) + } return nil } @@ -83,7 +81,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback isOk := false if !isRollback { rollbackFile := path.Join(global.Dir.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format(constant.DateTimeSlimLayout))) - if err := handleWebsiteBackup(website, recoverTask, path.Dir(rollbackFile), path.Base(rollbackFile), "", "", taskID); err != nil { + if err := handleWebsiteBackup(website, recoverTask, 0, path.Dir(rollbackFile), path.Base(rollbackFile), "", "", taskID); err != nil { return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err) } defer func() { @@ -200,10 +198,14 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback isOk = true return nil }, nil) - return recoverTask.Execute() + + go func() { + _ = recoverTask.Execute() + }() + return nil } -func handleWebsiteBackup(website *model.Website, parentTask *task.Task, backupDir, fileName, excludes, secret, taskID string) error { +func handleWebsiteBackup(website *model.Website, parentTask *task.Task, recordID uint, backupDir, fileName, excludes, secret, taskID string) error { var ( err error backupTask *task.Task @@ -216,11 +218,18 @@ func handleWebsiteBackup(website *model.Website, parentTask *task.Task, backupDi } } itemHandler := func() error { return doWebsiteBackup(website, backupTask, backupDir, fileName, excludes, secret) } - backupTask.AddSubTask(task.GetTaskName(website.Alias, task.TaskBackup, task.TaskScopeWebsite), func(t *task.Task) error { return itemHandler() }, nil) if parentTask != nil { return itemHandler() } - return backupTask.Execute() + backupTask.AddSubTaskWithOps(task.GetTaskName(website.Alias, task.TaskBackup, task.TaskScopeWebsite), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour) + go func() { + if err := backupTask.Execute(); err != nil { + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + return + } + backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess}) + }() + return nil } func doWebsiteBackup(website *model.Website, parentTask *task.Task, backupDir, fileName, excludes, secret string) error { @@ -252,7 +261,7 @@ func doWebsiteBackup(website *model.Website, parentTask *task.Task, backupDir, f return err } parentTask.LogStart(task.GetTaskName(app.Name, task.TaskBackup, task.TaskScopeApp)) - if err = handleAppBackup(&app, parentTask, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes, "", ""); err != nil { + if err = handleAppBackup(&app, parentTask, 0, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes, "", ""); err != nil { return err } parentTask.LogSuccess(task.GetTaskName(app.Name, task.TaskBackup, task.TaskScopeApp)) diff --git a/agent/constant/common.go b/agent/constant/common.go index 8bb7d23fd..7a9c38f7d 100644 --- a/agent/constant/common.go +++ b/agent/constant/common.go @@ -17,6 +17,8 @@ const ( TypeImagePush = "image-push" TypeImageBuild = "image-build" TypeComposeCreate = "compose-create" + + InterruptedMsg = "the task was interrupted due to the restart of the 1panel service" ) const ( diff --git a/agent/init/hook/hook.go b/agent/init/hook/hook.go index e0a094f73..64206a4ff 100644 --- a/agent/init/hook/hook.go +++ b/agent/init/hook/hook.go @@ -19,6 +19,7 @@ func Init() { initGlobalData() handleCronjobStatus() handleClamStatus() + handleRecordStatus() handleSnapStatus() handleOllamaModelStatus() @@ -44,26 +45,25 @@ func initGlobalData() { } func handleSnapStatus() { - msgFailed := "the task was interrupted due to the restart of the 1panel service" _ = global.DB.Model(&model.Snapshot{}).Where("status = ?", "OnSaveData"). Updates(map[string]interface{}{"status": constant.StatusSuccess}).Error _ = global.DB.Model(&model.Snapshot{}).Where("status = ?", constant.StatusWaiting). Updates(map[string]interface{}{ "status": constant.StatusFailed, - "message": msgFailed, + "message": constant.InterruptedMsg, }).Error _ = global.DB.Model(&model.Snapshot{}).Where("recover_status = ?", constant.StatusWaiting). Updates(map[string]interface{}{ "recover_status": constant.StatusFailed, - "recover_message": msgFailed, + "recover_message": constant.InterruptedMsg, }).Error _ = global.DB.Model(&model.Snapshot{}).Where("rollback_status = ?", constant.StatusWaiting). Updates(map[string]interface{}{ "rollback_status": constant.StatusFailed, - "rollback_message": msgFailed, + "rollback_message": constant.InterruptedMsg, }).Error } @@ -75,7 +75,7 @@ func handleCronjobStatus() { err := global.DB.Model(&model.JobRecords{}).Where("status = ?", constant.StatusWaiting). Updates(map[string]interface{}{ "status": constant.StatusFailed, - "message": "the task was interrupted due to the restart of the 1panel service", + "message": constant.InterruptedMsg, }).Error if err != nil { @@ -90,26 +90,25 @@ func handleCronjobStatus() { } func handleClamStatus() { - var jobRecords []model.ClamRecord _ = global.DB.Model(&model.Clam{}).Where("is_executing = ?", true).Updates(map[string]interface{}{"is_executing": false}).Error - _ = global.DB.Where("status = ?", constant.StatusWaiting).Find(&jobRecords).Error - for _, record := range jobRecords { - err := global.DB.Model(&model.ClamRecord{}).Where("status = ?", constant.StatusWaiting). - Updates(map[string]interface{}{ - "status": constant.StatusFailed, - "message": "the task was interrupted due to the restart of the 1panel service", - }).Error + _ = global.DB.Model(&model.ClamRecord{}).Where("status = ?", constant.StatusWaiting).Updates(map[string]interface{}{ + "status": constant.StatusFailed, + "message": constant.InterruptedMsg, + }).Error +} - if err != nil { - global.LOG.Errorf("Failed to update job ID: %v, Error:%v", record.ID, err) - continue - } - } +func handleRecordStatus() { + _ = global.DB.Model(&model.BackupRecord{}).Where("status = ?", constant.StatusWaiting).Updates(map[string]interface{}{ + "status": constant.StatusFailed, + "message": constant.InterruptedMsg, + }).Error } func handleOllamaModelStatus() { - message := "the task was interrupted due to the restart of the 1panel service" - _ = global.DB.Model(&model.OllamaModel{}).Where("status = ?", constant.StatusWaiting).Updates(map[string]interface{}{"status": constant.StatusCanceled, "message": message}).Error + _ = global.DB.Model(&model.OllamaModel{}).Where("status = ?", constant.StatusWaiting).Updates(map[string]interface{}{ + "status": constant.StatusCanceled, + "message": constant.InterruptedMsg, + }).Error } func handleCronJobAlert(cronjob *model.Cronjob) { diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go index 8e3791676..4cd7b6a12 100644 --- a/agent/init/migration/migrate.go +++ b/agent/init/migration/migrate.go @@ -41,6 +41,7 @@ func InitAgentDB() { migrations.UpdateMcpServerAddType, migrations.InitLocalSSHConn, migrations.InitLocalSSHShow, + migrations.InitRecordStatus, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go index eece1f128..5a53c23ff 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -563,3 +563,16 @@ var InitLocalSSHShow = &gormigrate.Migration{ return nil }, } + +var InitRecordStatus = &gormigrate.Migration{ + ID: "20250910-init-record-status", + Migrate: func(tx *gorm.DB) error { + if err := tx.AutoMigrate(&model.BackupRecord{}); err != nil { + return err + } + if err := tx.Model(&model.BackupRecord{}).Where("1 == 1").Updates(map[string]interface{}{"status": constant.StatusSuccess}).Error; err != nil { + return err + } + return nil + }, +} diff --git a/agent/utils/mysql/client/local.go b/agent/utils/mysql/client/local.go index b8ba02199..cc1c13986 100644 --- a/agent/utils/mysql/client/local.go +++ b/agent/utils/mysql/client/local.go @@ -235,9 +235,7 @@ func (r *Local) Backup(info BackupInfo) error { } global.LOG.Infof("start to %s | gzip > %s.gzip", dumpCmd, info.TargetDir+"/"+info.FileName) - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(info.Timeout*uint(time.Second))) - defer cancel() - cmd := exec.CommandContext(ctx, "docker", "exec", r.ContainerName, dumpCmd, "--routines", "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name) + cmd := exec.Command("docker", "exec", r.ContainerName, dumpCmd, "--routines", "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name) var stderr bytes.Buffer cmd.Stderr = &stderr @@ -261,9 +259,7 @@ func (r *Local) Recover(info RecoverInfo) error { mysqlCli = "mysql" } - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(info.Timeout*uint(time.Second))) - defer cancel() - cmd := exec.CommandContext(ctx, "docker", "exec", "-i", r.ContainerName, mysqlCli, "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name) + cmd := exec.Command("docker", "exec", "-i", r.ContainerName, mysqlCli, "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name) if strings.HasSuffix(info.SourceFile, ".gz") { gzipFile, err := os.Open(info.SourceFile) if err != nil { diff --git a/frontend/src/components/backup/index.vue b/frontend/src/components/backup/index.vue index 73590d57e..43994da8d 100644 --- a/frontend/src/components/backup/index.vue +++ b/frontend/src/components/backup/index.vue @@ -33,18 +33,32 @@ {{ $t('commons.button.delete') }} + + - + - + + + + @@ -249,6 +263,10 @@ const openTaskLog = (taskID: string) => { taskLogRef.value.openWithTaskID(taskID); }; +function selectable(row) { + return row.status !== 'Waiting'; +} + const backup = async (close: boolean) => { const taskID = newUUID(); let params = { @@ -378,6 +396,9 @@ const onBatchDelete = async (row: Backup.RecordInfo | null) => { const buttons = [ { label: i18n.global.t('commons.button.delete'), + disabled: (row: any) => { + return row.status === 'Waiting'; + }, click: (row: Backup.RecordInfo) => { onBatchDelete(row); }, @@ -385,7 +406,7 @@ const buttons = [ { label: i18n.global.t('commons.button.recover'), disabled: (row: any) => { - return row.size === 0; + return row.size === 0 || row.status === 'Failed'; }, click: (row: Backup.RecordInfo) => { onRecover(row); @@ -394,7 +415,7 @@ const buttons = [ { label: i18n.global.t('commons.button.download'), disabled: (row: any) => { - return row.size === 0; + return row.size === 0 || row.status === 'Failed'; }, click: (row: Backup.RecordInfo) => { onDownload(row);