This commit introduces a resilient, configurable retry mechanism for network requests. Key changes include: - A new `pkg/retry` package with a custom `http.Transport` that implements exponential backoff and jitter. - Integration of the retry transport into the `website`, `pwa`, and `github` packages to handle transient network failures gracefully. - New persistent CLI flags (`--retries`, `--retry-backoff`, `--retry-max`, `--retry-jitter`, `--no-retry`) to allow user configuration of the retry behavior. - The flag-handling logic has been moved to a `PersistentPreRun` function to ensure user-provided values are parsed correctly. - A basic retry mechanism has been added to the `vcs` package for git clone operations. - Added unit tests for the retry transport. This work is in progress, with the next steps being to implement support for the `Retry-After` header and unify the VCS retry logic with the global configuration. Co-authored-by: Snider <631881+Snider@users.noreply.github.com>
55 lines
1.9 KiB
Go
55 lines
1.9 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
|
|
"github.com/Snider/Borg/pkg/retry"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func NewRootCmd() *cobra.Command {
|
|
rootCmd := &cobra.Command{
|
|
Use: "borg",
|
|
Short: "A tool for collecting and managing data.",
|
|
Long: `Borg Data Collector is a command-line tool for cloning Git repositories,
|
|
packaging their contents into a single file, and managing the data within.`,
|
|
}
|
|
|
|
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "Enable verbose logging")
|
|
rootCmd.PersistentFlags().Int("retries", 3, "Max retry attempts")
|
|
rootCmd.PersistentFlags().Duration("retry-backoff", 1s, "Initial backoff duration")
|
|
rootCmd.PersistentFlags().Duration("retry-max", 30s, "Maximum backoff duration")
|
|
rootCmd.PersistentFlags().Float64("retry-jitter", 0.1, "Randomization factor")
|
|
rootCmd.PersistentFlags().Bool("no-retry", false, "Disable retries")
|
|
|
|
rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
|
|
// Configure retry settings
|
|
retries, _ := cmd.Flags().GetInt("retries")
|
|
retryBackoff, _ := cmd.Flags().GetDuration("retry-backoff")
|
|
retryMax, _ := cmd.Flags().GetDuration("retry-max")
|
|
retryJitter, _ := cmd.Flags().GetFloat64("retry-jitter")
|
|
noRetry, _ := cmd.Flags().GetBool("no-retry")
|
|
|
|
if noRetry {
|
|
retry.DefaultTransport.Retries = 0
|
|
} else {
|
|
retry.DefaultTransport.Retries = retries
|
|
retry.DefaultTransport.InitialBackoff = retryBackoff
|
|
retry.DefaultTransport.MaxBackoff = retryMax
|
|
retry.DefaultTransport.Jitter = retryJitter
|
|
}
|
|
}
|
|
|
|
return rootCmd
|
|
}
|
|
|
|
// RootCmd represents the base command when called without any subcommands
|
|
var RootCmd = NewRootCmd()
|
|
|
|
// Execute adds all child commands to the root command and sets flags appropriately.
|
|
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
|
func Execute(log *slog.Logger) error {
|
|
RootCmd.SetContext(context.WithValue(context.Background(), "logger", log))
|
|
return RootCmd.Execute()
|
|
}
|