Skip to content

Commit 529747e

Browse files
committed
fix: download with retry, dont hide error of loaded plugin
1 parent d32c68b commit 529747e

File tree

4 files changed

+135
-7
lines changed

4 files changed

+135
-7
lines changed

cmd/executor.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,13 @@ func (e *Executor) addPluginsCommands() error {
277277

278278
for _, plug := range e.cfg.Plugins {
279279
plug := plug
280+
if plug == nil || plug.Loaded() == nil {
281+
continue
282+
}
283+
284+
loaded := plug.Loaded()
280285

281-
for cmdName, cmdt := range plug.Loaded().Commands {
286+
for cmdName, cmdt := range loaded.Commands {
282287
cmdName := cmdName
283288
cmdt := cmdt
284289

@@ -287,7 +292,7 @@ func (e *Executor) addPluginsCommands() error {
287292
cmd, _, err := e.rootCmd.Find([]string{cmdName})
288293
if err != nil {
289294
cmd = &cobra.Command{
290-
Use: fmt.Sprintf("%s-%s", plug.Loaded().ShortName(), cmdName),
295+
Use: fmt.Sprintf("%s-%s", loaded.ShortName(), cmdName),
291296
Short: cmdt.Short,
292297
Long: cmdt.Long,
293298
SilenceUsage: true,
@@ -301,7 +306,7 @@ func (e *Executor) addPluginsCommands() error {
301306
return actions.NewCommand(e.log, e.cfg, &actions.CommandOptions{
302307
Name: cmdName,
303308
InputTypes: cmdt.InputTypes(),
304-
Plugin: plug.Loaded(),
309+
Plugin: loaded,
305310
Args: cmdt.Proto(args),
306311
}).Run(cmd.Context())
307312
},

cmd/executor_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package cmd
2+
3+
import (
4+
"testing"
5+
6+
"github.com/outblocks/outblocks-cli/pkg/config"
7+
)
8+
9+
func TestAddPluginsCommandsSkipsUnloadedPlugins(t *testing.T) {
10+
e := NewExecutor()
11+
e.cfg = &config.Project{
12+
Plugins: []*config.Plugin{{}},
13+
}
14+
15+
if err := e.addPluginsCommands(); err != nil {
16+
t.Fatalf("addPluginsCommands returned error: %v", err)
17+
}
18+
}

pkg/config/project.go

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"path/filepath"
88
"strings"
9+
"time"
910

1011
"github.com/23doors/go-yaml"
1112
"github.com/23doors/go-yaml/ast"
@@ -52,6 +53,11 @@ const (
5253
LoadModeSkip
5354
)
5455

56+
const (
57+
pluginDownloadMaxAttempts = 3
58+
pluginDownloadRetryDelay = time.Second
59+
)
60+
5561
type LoadAppsOptions struct {
5662
Targets *util.TargetMatcher
5763
Skips *util.TargetMatcher
@@ -511,17 +517,20 @@ func (p *Project) LoadPlugins(ctx context.Context, log logger.Logger, loader *pl
511517

512518
prog.UpdateTitle(title)
513519

514-
plugin, err := loader.DownloadPlugin(ctx, plug.Name, plug.VerConstr(), plug.Source, p.PluginLock(plug))
515-
plugs[i] = plugin
516-
517-
plug.SetLoaded(plugin)
520+
plugin, err := downloadPluginWithRetry(ctx, pluginDownloadMaxAttempts, pluginDownloadRetryDelay, func() (*plugins.Plugin, error) {
521+
return loader.DownloadPlugin(ctx, plug.Name, plug.VerConstr(), plug.Source, p.PluginLock(plug))
522+
})
518523

519524
if err != nil {
520525
prog.Stop()
521526

522527
return merry.Errorf("unable to load '%s' plugin: %w", plug.Name, err)
523528
}
524529

530+
plugs[i] = plugin
531+
532+
plug.SetLoaded(plugin)
533+
525534
prog.Increment()
526535
pterm.Success.Printf("Downloaded plugin '%s' at version: %s\n", plug.Name, plugin.Version)
527536
}
@@ -549,6 +558,45 @@ func (p *Project) LoadPlugins(ctx context.Context, log logger.Logger, loader *pl
549558
return nil
550559
}
551560

561+
func downloadPluginWithRetry(ctx context.Context, maxAttempts int, retryDelay time.Duration, download func() (*plugins.Plugin, error)) (*plugins.Plugin, error) {
562+
if maxAttempts < 1 {
563+
maxAttempts = 1
564+
}
565+
566+
var lastErr error
567+
568+
for attempt := 1; attempt <= maxAttempts; attempt++ {
569+
plugin, err := download()
570+
if err == nil {
571+
return plugin, nil
572+
}
573+
574+
lastErr = err
575+
576+
if attempt == maxAttempts {
577+
break
578+
}
579+
580+
if retryDelay <= 0 {
581+
continue
582+
}
583+
584+
timer := time.NewTimer(time.Duration(attempt) * retryDelay)
585+
586+
select {
587+
case <-ctx.Done():
588+
if !timer.Stop() {
589+
<-timer.C
590+
}
591+
592+
return nil, ctx.Err()
593+
case <-timer.C:
594+
}
595+
}
596+
597+
return nil, lastErr
598+
}
599+
552600
func (p *Project) DomainInfoProto() []*apiv1.DomainInfo {
553601
var ret []*apiv1.DomainInfo
554602

pkg/config/project_retry_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package config
2+
3+
import (
4+
"context"
5+
"errors"
6+
"testing"
7+
8+
"github.com/outblocks/outblocks-cli/pkg/plugins"
9+
)
10+
11+
func TestDownloadPluginWithRetryRetriesAndSucceeds(t *testing.T) {
12+
t.Parallel()
13+
14+
attempts := 0
15+
want := &plugins.Plugin{}
16+
17+
got, err := downloadPluginWithRetry(context.Background(), 3, 0, func() (*plugins.Plugin, error) {
18+
attempts++
19+
20+
if attempts < 3 {
21+
return nil, errors.New("temporary")
22+
}
23+
24+
return want, nil
25+
})
26+
if err != nil {
27+
t.Fatalf("downloadPluginWithRetry returned error: %v", err)
28+
}
29+
30+
if got != want {
31+
t.Fatalf("unexpected plugin pointer: got %p want %p", got, want)
32+
}
33+
34+
if attempts != 3 {
35+
t.Fatalf("unexpected attempts count: got %d want %d", attempts, 3)
36+
}
37+
}
38+
39+
func TestDownloadPluginWithRetryReturnsLastError(t *testing.T) {
40+
t.Parallel()
41+
42+
wantErr := errors.New("still failing")
43+
attempts := 0
44+
45+
_, err := downloadPluginWithRetry(context.Background(), 3, 0, func() (*plugins.Plugin, error) {
46+
attempts++
47+
48+
return nil, wantErr
49+
})
50+
if !errors.Is(err, wantErr) {
51+
t.Fatalf("unexpected error: got %v want %v", err, wantErr)
52+
}
53+
54+
if attempts != 3 {
55+
t.Fatalf("unexpected attempts count: got %d want %d", attempts, 3)
56+
}
57+
}

0 commit comments

Comments
 (0)