Skip to content

Commit 77bbbc3

Browse files
authored
Merge pull request #45 from utilitywarehouse/as-resilient
make mirror process more resilient
2 parents c823609 + 7d3d4a4 commit 77bbbc3

File tree

3 files changed

+43
-35
lines changed

3 files changed

+43
-35
lines changed

main.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,25 @@ func main() {
141141
os.Exit(1)
142142
}
143143

144-
// perform 1st mirror to ensure all repositories before starting controller
145-
// initial mirror might take longer
144+
allSucceed := true
145+
// perform 1st mirror to ensure all repositories syncs to indicate readiness
146+
// also initial mirror might take longer
146147
timeout := 2 * conf.Defaults.MirrorTimeout
147-
if err := repoPool.MirrorAll(ctx, timeout); err != nil {
148-
logger.Error("could not perform initial repositories mirror", "err", err)
149-
os.Exit(1)
148+
for _, repo := range conf.Repositories {
149+
mCtx, cancel := context.WithTimeout(ctx, timeout)
150+
err = repoPool.Mirror(mCtx, repo.Remote)
151+
cancel()
152+
if err != nil {
153+
allSucceed = false
154+
logger.Error("initial mirror failed", "repo", repo.Remote, "err", err)
155+
}
150156
}
151157

152158
if *flagOneTime {
153159
logger.Info("existing after first mirror")
160+
if !allSucceed {
161+
os.Exit(1)
162+
}
154163
os.Exit(0)
155164
}
156165

pkg/mirror/repo_pool.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package mirror
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"log/slog"
78
"os"
@@ -13,8 +14,8 @@ import (
1314
)
1415

1516
var (
16-
ErrExist = fmt.Errorf("repo already exist")
17-
ErrNotExist = fmt.Errorf("repo does not exist")
17+
ErrExist = errors.New("repo already exist")
18+
ErrNotExist = errors.New("repo does not exist")
1819
)
1920

2021
// RepoPool represents the collection of mirrored repositories

pkg/mirror/repository.go

+26-28
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package mirror
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"io/fs"
78
"log/slog"
@@ -25,6 +26,9 @@ const (
2526
)
2627

2728
var (
29+
ErrRepoMirrorFailed = errors.New("repository mirror failed")
30+
ErrRepoWTUpdateFailed = errors.New("repository worktree update failed")
31+
2832
gitExecutablePath string
2933
staleTimeout time.Duration = 10 * time.Second // time for stale worktrees to be cleaned up
3034

@@ -135,7 +139,7 @@ func NewRepository(repoConf RepositoryConfig, envs []string, log *slog.Logger) (
135139

136140
for _, wtc := range repoConf.Worktrees {
137141
if err := repo.AddWorktreeLink(wtc); err != nil {
138-
return nil, fmt.Errorf("unable to create worktree link err:%w", err)
142+
return nil, fmt.Errorf("unable to add worktree link err:%w", err)
139143
}
140144
}
141145
return repo, nil
@@ -477,35 +481,40 @@ func (r *Repository) Mirror(ctx context.Context) error {
477481
start := time.Now()
478482

479483
if err := r.init(ctx); err != nil {
480-
return fmt.Errorf("unable to init repo:%s err:%w", r.gitURL.Repo, err)
484+
r.log.Error("unable to init repo", "err", err)
485+
return ErrRepoMirrorFailed
481486
}
482487

483488
refs, err := r.fetch(ctx)
484489
if err != nil {
485-
return fmt.Errorf("unable to fetch repo:%s err:%w", r.gitURL.Repo, err)
490+
r.log.Error("unable to fetch repo", "err", err)
491+
return ErrRepoMirrorFailed
486492
}
487493

488494
fetchTime := time.Since(start)
489495

496+
var wtError error
490497
// worktree might need re-creating if it fails check
491-
// so always ensure worktree even if nothing fetched
498+
// so always ensure worktree even if nothing fetched.
499+
// continue on error to make sync process more resilient
492500
for _, wl := range r.workTreeLinks {
493501
if err := r.ensureWorktreeLink(ctx, wl); err != nil {
494-
return fmt.Errorf("unable to ensure worktree links repo:%s link:%s err:%w", r.gitURL.Repo, wl.link, err)
502+
r.log.Error("unable to ensure worktree links", "err", err)
503+
wtError = ErrRepoWTUpdateFailed
495504
}
496505
}
497506

498507
// clean-up can be skipped
499508
if len(refs) == 0 {
500-
return nil
509+
return wtError
501510
}
502511

503512
if err := r.cleanup(ctx); err != nil {
504-
return fmt.Errorf("unable to cleanup repo:%s err:%w", r.gitURL.Repo, err)
513+
r.log.Error("unable to cleanup repo", "err", err)
505514
}
506515

507516
r.log.Debug("mirror cycle complete", "time", time.Since(start), "fetch-time", fetchTime, "updated-refs", len(refs))
508-
return nil
517+
return wtError
509518
}
510519

511520
// RemoveWorktreeLink removes workTree link from the mirror repository.
@@ -742,6 +751,13 @@ func (r *Repository) ensureWorktreeLink(ctx context.Context, wl *WorkTreeLink) e
742751
if err != nil {
743752
return fmt.Errorf("unable to get hash for worktree:%s err:%w", wl.link, err)
744753
}
754+
755+
// if we get empty remote hash so either given worktree ref do not exits yet or
756+
// its removed from the remote
757+
if remoteHash == "" {
758+
return fmt.Errorf("hash not found for given ref:%s for worktree:%s", wl.ref, wl.link)
759+
}
760+
745761
var currentHash, currentPath string
746762

747763
// we do not care if we cant get old worktree path as we can create it
@@ -760,26 +776,6 @@ func (r *Repository) ensureWorktreeLink(ctx context.Context, wl *WorkTreeLink) e
760776
}
761777
}
762778

763-
// we got empty remote hash so either given worktree ref do not exits yet or
764-
// its removed from the remote
765-
if remoteHash == "" {
766-
wt, err := wl.currentWorktree()
767-
if err != nil {
768-
wl.log.Error("can't get current worktree", "err", err)
769-
return nil
770-
}
771-
if wt == "" {
772-
return nil
773-
}
774-
775-
wl.log.Info("remote hash is empty, removing old worktree", "path", currentPath)
776-
if err := r.removeWorktree(ctx, wt); err != nil {
777-
wl.log.Error("unable to remove old worktree", "err", err)
778-
}
779-
780-
return nil
781-
}
782-
783779
if currentHash == remoteHash {
784780
if wl.sanityCheckWorktree(ctx) {
785781
return nil
@@ -815,6 +811,8 @@ func (r *Repository) createWorktree(ctx context.Context, wl *WorkTreeLink, hash
815811

816812
// remove any existing worktree as we cant create new worktree if path is
817813
// not empty
814+
// since wtPath contains git hash it will always be either new path or
815+
// existing worktree with failed sanity check
818816
if err := r.removeWorktree(ctx, wtPath); err != nil {
819817
return wtPath, err
820818
}

0 commit comments

Comments
 (0)