detached 70b06a9

docs(mirror): say that sync --all runs a few pushes at a time and document the result handoff

commit
70b06a9f29d971fa41ac1d9c7c16d9bcb232d082
author
brice · · 2026-10-20 13:12 UTC
parent
798e82d
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
checks
4/4
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
4444
4545 - 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.
4646 - `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.
4848 - `--force` skips the no-op check and the 60 s throttle and lifts a pause. It never force-pushes.
4949 - Overlapping syncs of a repository coalesce; only one push runs at a time per repository.
5050
@@ -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 {
275275 return cmd
276276 }
277277
278+// newMirrorSyncCmd describes the server's wait bound (usecase.DefaultMirrorSyncWait, 8 s).
278279 func newMirrorSyncCmd(env *cliEnv) *cobra.Command {
279280 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 {
281282 if (all && len(args) == 0) || (!all && len(args) == 1) {
282283 return nil
283284 }
@@ -275,9 +275,10 @@ func newMirrorStatusCmd(env *cliEnv) *cobra.Command {
275 return cmd275 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 bool280 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 nil283 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
8181 }
8282 case <-f.done:
8383 }
84- m.mu.Lock()
84+ // run writes result and err before close(f.done): the close orders them before this read.
8585 res, err := f.result, f.err
86- m.mu.Unlock()
8786 res.Repo = repo
8887 return res, err
8988 }
@@ -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.err85 res, err := f.result, f.err
86- m.mu.Unlock()
87 res.Repo = repo86 res.Repo = repo
88 return res, err87 return res, err
89 }88 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 41

↑↓ moveenter openesc close