diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2023-05-11 16:25:46 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-11 08:25:46 +0000 |
commit | f6e029e6c7849d4361abf7f1d749b5d528364ac4 (patch) | |
tree | af285dd000dc48e4e94e717cf61a8b2437e99beb /services | |
parent | 58dfaf3a75a097088376a9c221784b3675ac9c48 (diff) | |
download | gitea-f6e029e6c7849d4361abf7f1d749b5d528364ac4.tar.gz gitea-f6e029e6c7849d4361abf7f1d749b5d528364ac4.zip |
Make repo migration cancelable and fix various bugs (#24605)
Replace #12917
Close #24601
Close #12845




---------
Co-authored-by: Yarden Shoham <git@yardenshoham.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Giteabot <teabot@gitea.io>
Diffstat (limited to 'services')
-rw-r--r-- | services/migrations/gitea_uploader.go | 5 | ||||
-rw-r--r-- | services/task/migrate.go | 49 | ||||
-rw-r--r-- | services/task/task.go | 2 |
3 files changed, 34 insertions, 22 deletions
diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 0eb34b5fe5..ad4293184e 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -923,9 +923,8 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { func (g *GiteaLocalUploader) Rollback() error { if g.repo != nil && g.repo.ID > 0 { g.gitRepo.Close() - if err := models.DeleteRepository(g.doer, g.repo.OwnerID, g.repo.ID); err != nil { - return err - } + + // do not delete the repository, otherwise the end users won't be able to see the last error message } return nil } diff --git a/services/task/migrate.go b/services/task/migrate.go index 03d083e596..98454482b5 100644 --- a/services/task/migrate.go +++ b/services/task/migrate.go @@ -7,8 +7,8 @@ import ( "errors" "fmt" "strings" + "time" - "code.gitea.io/gitea/models" admin_model "code.gitea.io/gitea/models/admin" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" @@ -28,13 +28,13 @@ import ( func handleCreateError(owner *user_model.User, err error) error { switch { case repo_model.IsErrReachLimitOfRepo(err): - return fmt.Errorf("You have already reached your limit of %d repositories", owner.MaxCreationLimit()) + return fmt.Errorf("you have already reached your limit of %d repositories", owner.MaxCreationLimit()) case repo_model.IsErrRepoAlreadyExist(err): - return errors.New("The repository name is already used") + return errors.New("the repository name is already used") case db.IsErrNameReserved(err): - return fmt.Errorf("The repository name '%s' is reserved", err.(db.ErrNameReserved).Name) + return fmt.Errorf("the repository name '%s' is reserved", err.(db.ErrNameReserved).Name) case db.IsErrNamePatternNotAllowed(err): - return fmt.Errorf("The pattern '%s' is not allowed in a repository name", err.(db.ErrNamePatternNotAllowed).Pattern) + return fmt.Errorf("the pattern '%s' is not allowed in a repository name", err.(db.ErrNamePatternNotAllowed).Pattern) default: return err } @@ -57,22 +57,17 @@ func runMigrateTask(t *admin_model.Task) (err error) { log.Error("FinishMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d] failed: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, err) } + log.Error("runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d] failed: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, err) + t.EndTime = timeutil.TimeStampNow() t.Status = structs.TaskStatusFailed t.Message = err.Error() - // Ensure that the repo loaded before we zero out the repo ID from the task - thus ensuring that we can delete it - _ = t.LoadRepo() - t.RepoID = 0 - if err := t.UpdateCols("status", "errors", "repo_id", "end_time"); err != nil { + if err := t.UpdateCols("status", "message", "end_time"); err != nil { log.Error("Task UpdateCols failed: %v", err) } - if t.Repo != nil { - if errDelete := models.DeleteRepository(t.Doer, t.OwnerID, t.Repo.ID); errDelete != nil { - log.Error("DeleteRepository: %v", errDelete) - } - } + // then, do not delete the repository, otherwise the users won't be able to see the last error }() if err = t.LoadRepo(); err != nil { @@ -100,7 +95,7 @@ func runMigrateTask(t *admin_model.Task) (err error) { opts.MigrateToRepoID = t.RepoID pm := process.GetManager() - ctx, _, finished := pm.AddContext(graceful.GetManager().ShutdownContext(), fmt.Sprintf("MigrateTask: %s/%s", t.Owner.Name, opts.RepoName)) + ctx, cancel, finished := pm.AddContext(graceful.GetManager().ShutdownContext(), fmt.Sprintf("MigrateTask: %s/%s", t.Owner.Name, opts.RepoName)) defer finished() t.StartTime = timeutil.TimeStampNow() @@ -109,6 +104,23 @@ func runMigrateTask(t *admin_model.Task) (err error) { return } + // check whether the task should be canceled, this goroutine is also managed by process manager + go func() { + for { + select { + case <-time.After(2 * time.Second): + case <-ctx.Done(): + return + } + task, _ := admin_model.GetMigratingTask(t.RepoID) + if task != nil && task.Status != structs.TaskStatusRunning { + log.Debug("MigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d] is canceled due to status is not 'running'", t.ID, t.DoerID, t.RepoID, t.OwnerID) + cancel() + return + } + } + }() + t.Repo, err = migrations.MigrateRepository(ctx, t.Doer, t.Owner.Name, *opts, func(format string, args ...interface{}) { message := admin_model.TranslatableMessage{ Format: format, @@ -118,13 +130,14 @@ func runMigrateTask(t *admin_model.Task) (err error) { t.Message = string(bs) _ = t.UpdateCols("message") }) + if err == nil { log.Trace("Repository migrated [%d]: %s/%s", t.Repo.ID, t.Owner.Name, t.Repo.Name) return } if repo_model.IsErrRepoAlreadyExist(err) { - err = errors.New("The repository name is already used") + err = errors.New("the repository name is already used") return } @@ -132,9 +145,9 @@ func runMigrateTask(t *admin_model.Task) (err error) { err = util.SanitizeErrorCredentialURLs(err) if strings.Contains(err.Error(), "Authentication failed") || strings.Contains(err.Error(), "could not read Username") { - return fmt.Errorf("Authentication failed: %w", err) + return fmt.Errorf("authentication failed: %w", err) } else if strings.Contains(err.Error(), "fatal:") { - return fmt.Errorf("Migration failed: %w", err) + return fmt.Errorf("migration failed: %w", err) } // do not be tempted to coalesce this line with the return diff --git a/services/task/task.go b/services/task/task.go index 4f1ba3a60b..493586a645 100644 --- a/services/task/task.go +++ b/services/task/task.go @@ -95,7 +95,7 @@ func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*adm DoerID: doer.ID, OwnerID: u.ID, Type: structs.TaskTypeMigrateRepo, - Status: structs.TaskStatusQueue, + Status: structs.TaskStatusQueued, PayloadContent: string(bs), } |