diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 9c5323bebe..e447f54275 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -209,6 +209,12 @@ var flags = []cli.Flag{ // // resource limit parameters // + &cli.DurationFlag{ + EnvVars: []string{"WOODPECKER_FORGE_TIMEOUT"}, + Name: "forge-timeout", + Usage: "how many seconds before timeout when fetching the Woodpecker configuration from a Forge", + Value: time.Second * 3, + }, &cli.Int64Flag{ EnvVars: []string{"WOODPECKER_LIMIT_MEM_SWAP"}, Name: "limit-mem-swap", diff --git a/cmd/server/server.go b/cmd/server/server.go index 7a26b734d9..c81a2cb662 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -269,6 +269,7 @@ func setupEvilGlobals(c *cli.Context, v store.Store, f forge.Forge) { // forge server.Config.Services.Forge = f + server.Config.Services.Timeout = c.Duration("forge-timeout") // services server.Config.Services.Queue = setupQueue(c, v) diff --git a/docs/docs/30-administration/10-server-config.md b/docs/docs/30-administration/10-server-config.md index 62cb9fe687..62a183709a 100644 --- a/docs/docs/30-administration/10-server-config.md +++ b/docs/docs/30-administration/10-server-config.md @@ -377,6 +377,13 @@ Example: `WOODPECKER_LIMIT_CPU_SET=1,2` Specify a configuration service endpoint, see [Configuration Extension](./100-external-configuration-api.md) + +### `WOODPECKER_FORGE_TIMEOUT` +> Default: 3sec + +Specify how many seconds before timeout when fetching the Woodpecker configuration from a Forge + + --- ### `WOODPECKER_GITHUB_...` diff --git a/server/config.go b/server/config.go index 774f4ea0b2..7bb7f12053 100644 --- a/server/config.go +++ b/server/config.go @@ -39,6 +39,7 @@ var Config = struct { Registries model.RegistryService Environ model.EnvironService Forge forge.Forge + Timeout time.Duration Membership cache.MembershipService ConfigService config.Extension SignaturePrivateKey crypto.PrivateKey diff --git a/server/forge/configFetcher.go b/server/forge/configFetcher.go index 24ee17f13b..53c8656e08 100644 --- a/server/forge/configFetcher.go +++ b/server/forge/configFetcher.go @@ -39,28 +39,27 @@ type configFetcher struct { repo *model.Repo pipeline *model.Pipeline configExtension config.Extension + timeout time.Duration } -func NewConfigFetcher(forge Forge, configExtension config.Extension, user *model.User, repo *model.Repo, pipeline *model.Pipeline) ConfigFetcher { +func NewConfigFetcher(forge Forge, timeout time.Duration, configExtension config.Extension, user *model.User, repo *model.Repo, pipeline *model.Pipeline) ConfigFetcher { return &configFetcher{ forge: forge, user: user, repo: repo, pipeline: pipeline, configExtension: configExtension, + timeout: timeout, } } -// configFetchTimeout determine seconds the configFetcher wait until cancel fetch process -var configFetchTimeout = time.Second * 3 - // Fetch pipeline config from source forge func (cf *configFetcher) Fetch(ctx context.Context) (files []*types.FileMeta, err error) { log.Trace().Msgf("Start Fetching config for '%s'", cf.repo.FullName) // try to fetch 3 times for i := 0; i < 3; i++ { - files, err = cf.fetch(ctx, configFetchTimeout, strings.TrimSpace(cf.repo.Config)) + files, err = cf.fetch(ctx, time.Second*cf.timeout, strings.TrimSpace(cf.repo.Config)) if err != nil { log.Trace().Err(err).Msgf("%d. try failed", i+1) } @@ -69,7 +68,7 @@ func (cf *configFetcher) Fetch(ctx context.Context) (files []*types.FileMeta, er } if cf.configExtension != nil && cf.configExtension.IsConfigured() { - fetchCtx, cancel := context.WithTimeout(ctx, configFetchTimeout) + fetchCtx, cancel := context.WithTimeout(ctx, cf.timeout) defer cancel() // ok here as we only try http fetching once, returning on fail and success log.Trace().Msgf("ConfigFetch[%s]: getting config from external http service", cf.repo.FullName) diff --git a/server/forge/configFetcher_test.go b/server/forge/configFetcher_test.go index f6c4b101dc..7754556890 100644 --- a/server/forge/configFetcher_test.go +++ b/server/forge/configFetcher_test.go @@ -25,6 +25,7 @@ import ( "net/http/httptest" "path/filepath" "testing" + "time" "github.com/go-ap/httpsig" "github.com/stretchr/testify/assert" @@ -314,6 +315,7 @@ func TestFetch(t *testing.T) { configFetcher := forge.NewConfigFetcher( f, + time.Second*3, config.NewHTTP("", ""), &model.User{Token: "xxx"}, repo, @@ -519,6 +521,7 @@ func TestFetchFromConfigService(t *testing.T) { configFetcher := forge.NewConfigFetcher( f, + time.Second*3, configAPI, &model.User{Token: "xxx"}, repo, diff --git a/server/pipeline/create.go b/server/pipeline/create.go index 3dc2271562..eca1ed2bcb 100644 --- a/server/pipeline/create.go +++ b/server/pipeline/create.go @@ -60,7 +60,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline ) // fetch the pipeline file from the forge - configFetcher := forge.NewConfigFetcher(server.Config.Services.Forge, server.Config.Services.ConfigService, repoUser, repo, pipeline) + configFetcher := forge.NewConfigFetcher(server.Config.Services.Forge, server.Config.Services.Timeout, server.Config.Services.ConfigService, repoUser, repo, pipeline) forgeYamlConfigs, configFetchErr = configFetcher.Fetch(ctx) if configFetchErr == nil { filtered, parseErr = checkIfFiltered(pipeline, forgeYamlConfigs)