mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-12 22:10:25 +00:00
[v15.0/forgejo] fix: make package cleanup work again (#12452)
**Backport:** https://codeberg.org/forgejo/forgejo/pulls/12446 - Regression of forgejo/forgejo!11776 (and forgejo/forgejo!11881) - Scope of the transaction is moved to a per-package cleanup rule basis. This is also a enhancement for scaling (already deployed on Codeberg for a while). - Package cleanup is now run with `RetryTx`, because rebuilding repository files runs `RetryTx` and it could indicate to retry the whole transaction. - Previously it would error and say running `RetryTx` in a transaction was not possible, this is now possible. Nested `RetryTx` is always allowed, matching of which errors to retry is still the responsible of the inner `RetryTx`. Co-authored-by: Gusted <postmaster@gusted.xyz> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12452 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
parent
80476238ab
commit
1b7b1e4fe5
4 changed files with 171 additions and 75 deletions
|
|
@ -33,78 +33,68 @@ func CleanupTask(ctx context.Context, olderThan time.Duration) error {
|
|||
return CleanupExpiredData(ctx, olderThan)
|
||||
}
|
||||
|
||||
func ExecuteCleanupRules(outerCtx context.Context) error {
|
||||
ctx, committer, err := db.TxContext(outerCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
err = packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error {
|
||||
select {
|
||||
case <-outerCtx.Done():
|
||||
return db.ErrCancelledf("While processing package cleanup rules")
|
||||
default:
|
||||
}
|
||||
|
||||
versionsToRemove, err := GetCleanupTargets(ctx, pcr, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: GetCleanupTargets failed: %w", pcr.ID, err)
|
||||
}
|
||||
|
||||
anyVersionDeleted := false
|
||||
packageWithVersionDeleted := make(map[int64]bool) // set of Package.ID's where at least one package version was removed
|
||||
for _, ct := range versionsToRemove {
|
||||
if err := packages_service.DeletePackageVersionAndReferences(ctx, ct.PackageVersion); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %w", pcr.ID, err)
|
||||
func ExecuteCleanupRules(ctx context.Context) error {
|
||||
return packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error {
|
||||
// We have no errors to retry on, because we have no evidence we need any in
|
||||
// this area. What we do retry on is when a nested `db.RetryTx` indicates to
|
||||
// retry the whole transaction.
|
||||
return db.RetryTx(ctx, db.RetryConfig{
|
||||
AttemptCount: 3,
|
||||
}, func(ctx context.Context) error {
|
||||
versionsToRemove, err := GetCleanupTargets(ctx, pcr, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: GetCleanupTargets failed: %w", pcr.ID, err)
|
||||
}
|
||||
packageWithVersionDeleted[ct.Package.ID] = true
|
||||
anyVersionDeleted = true
|
||||
}
|
||||
|
||||
if pcr.Type == packages_model.TypeCargo {
|
||||
for packageID := range packageWithVersionDeleted {
|
||||
owner, err := user_model.GetUserByID(ctx, pcr.OwnerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserByID failed: %w", err)
|
||||
anyVersionDeleted := false
|
||||
packageWithVersionDeleted := make(map[int64]bool) // set of Package.ID's where at least one package version was removed
|
||||
for _, ct := range versionsToRemove {
|
||||
if err := packages_service.DeletePackageVersionAndReferences(ctx, ct.PackageVersion); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %w", pcr.ID, err)
|
||||
}
|
||||
if err := cargo_service.UpdatePackageIndexIfExists(ctx, owner, owner, packageID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: cargo.UpdatePackageIndexIfExists failed: %w", pcr.ID, err)
|
||||
packageWithVersionDeleted[ct.Package.ID] = true
|
||||
anyVersionDeleted = true
|
||||
}
|
||||
|
||||
if pcr.Type == packages_model.TypeCargo {
|
||||
for packageID := range packageWithVersionDeleted {
|
||||
owner, err := user_model.GetUserByID(ctx, pcr.OwnerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserByID failed: %w", err)
|
||||
}
|
||||
if err := cargo_service.UpdatePackageIndexIfExists(ctx, owner, owner, packageID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: cargo.UpdatePackageIndexIfExists failed: %w", pcr.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if anyVersionDeleted {
|
||||
switch pcr.Type {
|
||||
case packages_model.TypeDebian:
|
||||
if err := debian_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: debian.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
case packages_model.TypeAlpine:
|
||||
if err := alpine_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: alpine.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
case packages_model.TypeRpm:
|
||||
if err := rpm_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: rpm.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
case packages_model.TypeArch:
|
||||
if err := arch_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: arch.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
case packages_model.TypeAlt:
|
||||
if err := alt_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: alt.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
if anyVersionDeleted {
|
||||
switch pcr.Type {
|
||||
case packages_model.TypeDebian:
|
||||
if err := debian_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: debian.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
case packages_model.TypeAlpine:
|
||||
if err := alpine_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: alpine.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
case packages_model.TypeRpm:
|
||||
if err := rpm_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: rpm.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
case packages_model.TypeArch:
|
||||
if err := arch_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: arch.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
case packages_model.TypeAlt:
|
||||
if err := alt_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
|
||||
return fmt.Errorf("CleanupRule [%d]: alt.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return nil
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
type CleanupTarget struct {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue