docs(mirror): say that sync --all runs a few pushes at a time and document the result handoff
3 files · +4 -4
M docs/mirror.md +1 -1
| @@ -44,7 +44,7 @@ URLs are `git@host:path` or `ssh://[user@]host[:port]/path`, with no password. T | |||
| 44 | 44 | ||
| 45 | 45 | - On the cron schedule. A push to ermite only marks the repository as changed; the next due cron tick syncs it. A tick with nothing new does nothing. | |
| 46 | 46 | - `ermite mirror sync <repo>` or `ermite mirror sync --all` (owner only) syncs now; a repository needs admin rights. `--all` skips repositories without a mirror, continues past failures, prints one row per repository and exits with status 1 if any failed. | |
| 47 | - | - A manual sync waits at most about 8 s (the edge proxy cuts responses at 10 s, the CLI at 30 s, while an SSH push to an unreachable host can take 30 s or more). `--all` starts every repository at once, so the wait is one push, not one per repository. A push still running then is shown as `QUEUED true`; the CLI says so on stderr, the sync continues on the server, and `ermite mirror status` shows its outcome. | |
| 47 | + | - A manual sync waits at most about 8 s (the edge proxy cuts responses at 10 s, the CLI at 30 s, while an SSH push to an unreachable host can take 30 s or more). `--all` queues every repository at once and the server pushes a few at a time (2 in parallel), so the wait stays one bound, not one per repository. A sync still running or still waiting for its turn then is shown as `QUEUED true`; the CLI says so on stderr, the sync continues on the server, and `ermite mirror status` shows its outcome. | |
| 48 | 48 | - `--force` skips the no-op check and the 60 s throttle and lifts a pause. It never force-pushes. | |
| 49 | 49 | - Overlapping syncs of a repository coalesce; only one push runs at a time per repository. | |
| 50 | 50 | ||
| @@ -44,7 +44,7 @@ URLs are `git@host:path` or `ssh://[user@]host[:port]/path`, with no password. T | |||||
| 44 | 44 | ||||
| 45 | - On the cron schedule. A push to ermite only marks the repository as changed; the next due cron tick syncs it. A tick with nothing new does nothing. | 45 | - On the cron schedule. A push to ermite only marks the repository as changed; the next due cron tick syncs it. A tick with nothing new does nothing. | ||
| 46 | - `ermite mirror sync <repo>` or `ermite mirror sync --all` (owner only) syncs now; a repository needs admin rights. `--all` skips repositories without a mirror, continues past failures, prints one row per repository and exits with status 1 if any failed. | 46 | - `ermite mirror sync <repo>` or `ermite mirror sync --all` (owner only) syncs now; a repository needs admin rights. `--all` skips repositories without a mirror, continues past failures, prints one row per repository and exits with status 1 if any failed. | ||
| 47 | - | - A manual sync waits at most about 8 s (the edge proxy cuts responses at 10 s, the CLI at 30 s, while an SSH push to an unreachable host can take 30 s or more). `--all` starts every repository at once, so the wait is one push, not one per repository. A push still running then is shown as `QUEUED true`; the CLI says so on stderr, the sync continues on the server, and `ermite mirror status` shows its outcome. | 47 | + | - A manual sync waits at most about 8 s (the edge proxy cuts responses at 10 s, the CLI at 30 s, while an SSH push to an unreachable host can take 30 s or more). `--all` queues every repository at once and the server pushes a few at a time (2 in parallel), so the wait stays one bound, not one per repository. A sync still running or still waiting for its turn then is shown as `QUEUED true`; the CLI says so on stderr, the sync continues on the server, and `ermite mirror status` shows its outcome. |
| 48 | - `--force` skips the no-op check and the 60 s throttle and lifts a pause. It never force-pushes. | 48 | - `--force` skips the no-op check and the 60 s throttle and lifts a pause. It never force-pushes. | ||
| 49 | - Overlapping syncs of a repository coalesce; only one push runs at a time per repository. | 49 | - Overlapping syncs of a repository coalesce; only one push runs at a time per repository. | ||
| 50 | 50 | ||||
M internal/app/cli_mirror.go +2 -1
| @@ -275,9 +275,10 @@ func newMirrorStatusCmd(env *cliEnv) *cobra.Command { | |||
| 275 | 275 | return cmd | |
| 276 | 276 | } | |
| 277 | 277 | ||
| 278 | + | // newMirrorSyncCmd describes the server's wait bound (usecase.DefaultMirrorSyncWait, 8 s). | |
| 278 | 279 | func newMirrorSyncCmd(env *cliEnv) *cobra.Command { | |
| 279 | 280 | var all, force bool | |
| 280 | - | cmd := &cobra.Command{Use: "sync <repo>|--all", Short: "Sync mirrors now", Long: "Sync one repository, or every repository with --all (owner only).\nRepositories are pushed concurrently. The command waits about 8 s; a push still running then is reported as queued,\nkeeps running on the server, and its outcome is shown by `ermite mirror status`.\n--force never force-pushes: it only skips the no-op check and throttle and lifts a pause.", Args: func(_ *cobra.Command, args []string) error { | |
| 281 | + | cmd := &cobra.Command{Use: "sync <repo>|--all", Short: "Sync mirrors now", Long: "Sync one repository, or every repository with --all (owner only).\nThe server pushes a few repositories at a time. The command waits about 8 s; a sync still running or waiting\nthen is reported as queued, keeps going on the server, and its outcome is shown by `ermite mirror status`.\n--force never force-pushes: it only skips the no-op check and throttle and lifts a pause.", Args: func(_ *cobra.Command, args []string) error { | |
| 281 | 282 | if (all && len(args) == 0) || (!all && len(args) == 1) { | |
| 282 | 283 | return nil | |
| 283 | 284 | } | |
| @@ -275,9 +275,10 @@ func newMirrorStatusCmd(env *cliEnv) *cobra.Command { | |||||
| 275 | return cmd | 275 | return cmd | ||
| 276 | } | 276 | } | ||
| 277 | 277 | ||||
| 278 | + | // newMirrorSyncCmd describes the server's wait bound (usecase.DefaultMirrorSyncWait, 8 s). | |||
| 278 | func newMirrorSyncCmd(env *cliEnv) *cobra.Command { | 279 | func newMirrorSyncCmd(env *cliEnv) *cobra.Command { | ||
| 279 | var all, force bool | 280 | var all, force bool | ||
| 280 | - | cmd := &cobra.Command{Use: "sync <repo>|--all", Short: "Sync mirrors now", Long: "Sync one repository, or every repository with --all (owner only).\nRepositories are pushed concurrently. The command waits about 8 s; a push still running then is reported as queued,\nkeeps running on the server, and its outcome is shown by `ermite mirror status`.\n--force never force-pushes: it only skips the no-op check and throttle and lifts a pause.", Args: func(_ *cobra.Command, args []string) error { | 281 | + | cmd := &cobra.Command{Use: "sync <repo>|--all", Short: "Sync mirrors now", Long: "Sync one repository, or every repository with --all (owner only).\nThe server pushes a few repositories at a time. The command waits about 8 s; a sync still running or waiting\nthen is reported as queued, keeps going on the server, and its outcome is shown by `ermite mirror status`.\n--force never force-pushes: it only skips the no-op check and throttle and lifts a pause.", Args: func(_ *cobra.Command, args []string) error { |
| 281 | if (all && len(args) == 0) || (!all && len(args) == 1) { | 282 | if (all && len(args) == 0) || (!all && len(args) == 1) { | ||
| 282 | return nil | 283 | return nil | ||
| 283 | } | 284 | } | ||
M internal/usecase/mirrors_sync.go +1 -2
| @@ -81,9 +81,8 @@ func (m *Mirrors) await(ctx, wctx context.Context, repo domain.RepoName, f *mirr | |||
| 81 | 81 | } | |
| 82 | 82 | case <-f.done: | |
| 83 | 83 | } | |
| 84 | - | m.mu.Lock() | |
| 84 | + | // run writes result and err before close(f.done): the close orders them before this read. | |
| 85 | 85 | res, err := f.result, f.err | |
| 86 | - | m.mu.Unlock() | |
| 87 | 86 | res.Repo = repo | |
| 88 | 87 | return res, err | |
| 89 | 88 | } | |
| @@ -81,9 +81,8 @@ func (m *Mirrors) await(ctx, wctx context.Context, repo domain.RepoName, f *mirr | |||||
| 81 | } | 81 | } | ||
| 82 | case <-f.done: | 82 | case <-f.done: | ||
| 83 | } | 83 | } | ||
| 84 | - | m.mu.Lock() | 84 | + | // run writes result and err before close(f.done): the close orders them before this read. |
| 85 | res, err := f.result, f.err | 85 | res, err := f.result, f.err | ||
| 86 | - | m.mu.Unlock() | |||
| 87 | res.Repo = repo | 86 | res.Repo = repo | ||
| 88 | return res, err | 87 | return res, err | ||
| 89 | } | 88 | } | ||