Skip to content

Commit 52230fa

Browse files
authored
feat: make default autobuild poll intervals configurable (#1618)
* feat: make default poll intervals for autobuild and ssh ttl polling configurable
1 parent 992b583 commit 52230fa

File tree

6 files changed

+104
-20
lines changed

6 files changed

+104
-20
lines changed

cli/cliflag/cliflag.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"os"
1616
"strconv"
1717
"strings"
18+
"time"
1819

1920
"github.com/spf13/pflag"
2021
)
@@ -83,6 +84,23 @@ func BoolVarP(flagset *pflag.FlagSet, ptr *bool, name string, shorthand string,
8384
flagset.BoolVarP(ptr, name, shorthand, valb, fmtUsage(usage, env))
8485
}
8586

87+
// DurationVarP sets a time.Duration flag on the given flag set.
88+
func DurationVarP(flagset *pflag.FlagSet, ptr *time.Duration, name string, shorthand string, env string, def time.Duration, usage string) {
89+
val, ok := os.LookupEnv(env)
90+
if !ok || val == "" {
91+
flagset.DurationVarP(ptr, name, shorthand, def, fmtUsage(usage, env))
92+
return
93+
}
94+
95+
valb, err := time.ParseDuration(val)
96+
if err != nil {
97+
flagset.DurationVarP(ptr, name, shorthand, def, fmtUsage(usage, env))
98+
return
99+
}
100+
101+
flagset.DurationVarP(ptr, name, shorthand, valb, fmtUsage(usage, env))
102+
}
103+
86104
func fmtUsage(u string, env string) string {
87105
if env == "" {
88106
return fmt.Sprintf("%s.", u)

cli/cliflag/cliflag_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"strconv"
66
"testing"
7+
"time"
78

89
"github.com/spf13/pflag"
910
"github.com/stretchr/testify/require"
@@ -183,6 +184,45 @@ func TestCliflag(t *testing.T) {
183184
require.NoError(t, err)
184185
require.Equal(t, def, got)
185186
})
187+
188+
t.Run("DurationDefault", func(t *testing.T) {
189+
var ptr time.Duration
190+
flagset, name, shorthand, env, usage := randomFlag()
191+
def, _ := cryptorand.Duration()
192+
193+
cliflag.DurationVarP(flagset, &ptr, name, shorthand, env, def, usage)
194+
got, err := flagset.GetDuration(name)
195+
require.NoError(t, err)
196+
require.Equal(t, def, got)
197+
require.Contains(t, flagset.FlagUsages(), usage)
198+
require.Contains(t, flagset.FlagUsages(), fmt.Sprintf(" - consumes $%s", env))
199+
})
200+
201+
t.Run("DurationEnvVar", func(t *testing.T) {
202+
var ptr time.Duration
203+
flagset, name, shorthand, env, usage := randomFlag()
204+
envValue, _ := cryptorand.Duration()
205+
t.Setenv(env, envValue.String())
206+
def, _ := cryptorand.Duration()
207+
208+
cliflag.DurationVarP(flagset, &ptr, name, shorthand, env, def, usage)
209+
got, err := flagset.GetDuration(name)
210+
require.NoError(t, err)
211+
require.Equal(t, envValue, got)
212+
})
213+
214+
t.Run("DurationFailParse", func(t *testing.T) {
215+
var ptr time.Duration
216+
flagset, name, shorthand, env, usage := randomFlag()
217+
envValue, _ := cryptorand.String(10)
218+
t.Setenv(env, envValue)
219+
def, _ := cryptorand.Duration()
220+
221+
cliflag.DurationVarP(flagset, &ptr, name, shorthand, env, def, usage)
222+
got, err := flagset.GetDuration(name)
223+
require.NoError(t, err)
224+
require.Equal(t, def, got)
225+
})
186226
}
187227

188228
func randomFlag() (*pflag.FlagSet, string, string, string, string) {

cli/server.go

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,18 @@ import (
6060
// nolint:gocyclo
6161
func server() *cobra.Command {
6262
var (
63-
accessURL string
64-
address string
65-
promEnabled bool
66-
promAddress string
67-
pprofEnabled bool
68-
pprofAddress string
69-
cacheDir string
70-
dev bool
71-
devUserEmail string
72-
devUserPassword string
73-
postgresURL string
63+
accessURL string
64+
address string
65+
autobuildPollInterval time.Duration
66+
promEnabled bool
67+
promAddress string
68+
pprofEnabled bool
69+
pprofAddress string
70+
cacheDir string
71+
dev bool
72+
devUserEmail string
73+
devUserPassword string
74+
postgresURL string
7475
// provisionerDaemonCount is a uint8 to ensure a number > 0.
7576
provisionerDaemonCount uint8
7677
oauth2GithubClientID string
@@ -361,10 +362,10 @@ func server() *cobra.Command {
361362
return xerrors.Errorf("notify systemd: %w", err)
362363
}
363364

364-
lifecyclePoller := time.NewTicker(time.Minute)
365-
defer lifecyclePoller.Stop()
366-
lifecycleExecutor := executor.New(cmd.Context(), options.Database, logger, lifecyclePoller.C)
367-
lifecycleExecutor.Run()
365+
autobuildPoller := time.NewTicker(autobuildPollInterval)
366+
defer autobuildPoller.Stop()
367+
autobuildExecutor := executor.New(cmd.Context(), options.Database, logger, autobuildPoller.C)
368+
autobuildExecutor.Run()
368369

369370
// Because the graceful shutdown includes cleaning up workspaces in dev mode, we're
370371
// going to make it harder to accidentally skip the graceful shutdown by hitting ctrl+c
@@ -454,6 +455,7 @@ func server() *cobra.Command {
454455
},
455456
}
456457

458+
cliflag.DurationVarP(root.Flags(), &autobuildPollInterval, "autobuild-poll-interval", "", "CODER_AUTOBUILD_POLL_INTERVAL", time.Minute, "Specifies the interval at which to poll for and execute automated workspace build operations.")
457459
cliflag.StringVarP(root.Flags(), &accessURL, "access-url", "", "CODER_ACCESS_URL", "", "Specifies the external URL to access Coder.")
458460
cliflag.StringVarP(root.Flags(), &address, "address", "a", "CODER_ADDRESS", "127.0.0.1:3000", "The address to serve the API and dashboard.")
459461
cliflag.BoolVarP(root.Flags(), &promEnabled, "prometheus-enable", "", "CODER_PROMETHEUS_ENABLE", false, "Enable serving prometheus metrics on the addressdefined by --prometheus-address.")

cli/ssh.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@ import (
2525
"github.com/coder/coder/cryptorand"
2626
)
2727

28-
var autostopPollInterval = 30 * time.Second
28+
var workspacePollInterval = time.Minute
2929
var autostopNotifyCountdown = []time.Duration{30 * time.Minute}
3030

3131
func ssh() *cobra.Command {
3232
var (
33-
stdio bool
34-
shuffle bool
33+
stdio bool
34+
shuffle bool
35+
wsPollInterval time.Duration
3536
)
3637
cmd := &cobra.Command{
3738
Annotations: workspaceCommand,
@@ -155,6 +156,7 @@ func ssh() *cobra.Command {
155156
}
156157
cliflag.BoolVarP(cmd.Flags(), &stdio, "stdio", "", "CODER_SSH_STDIO", false, "Specifies whether to emit SSH output over stdin/stdout.")
157158
cliflag.BoolVarP(cmd.Flags(), &shuffle, "shuffle", "", "CODER_SSH_SHUFFLE", false, "Specifies whether to choose a random workspace")
159+
cliflag.DurationVarP(cmd.Flags(), &wsPollInterval, "workspace-poll-interval", "", "CODER_WORKSPACE_POLL_INTERVAL", workspacePollInterval, "Specifies how often to poll for workspace automated shutdown.")
158160
_ = cmd.Flags().MarkHidden("shuffle")
159161

160162
return cmd
@@ -252,14 +254,14 @@ func getWorkspaceAndAgent(cmd *cobra.Command, client *codersdk.Client, orgID uui
252254
func tryPollWorkspaceAutostop(ctx context.Context, client *codersdk.Client, workspace codersdk.Workspace) (stop func()) {
253255
lock := flock.New(filepath.Join(os.TempDir(), "coder-autostop-notify-"+workspace.ID.String()))
254256
condition := notifyCondition(ctx, client, workspace.ID, lock)
255-
return notify.Notify(condition, autostopPollInterval, autostopNotifyCountdown...)
257+
return notify.Notify(condition, workspacePollInterval, autostopNotifyCountdown...)
256258
}
257259

258260
// Notify the user if the workspace is due to shutdown.
259261
func notifyCondition(ctx context.Context, client *codersdk.Client, workspaceID uuid.UUID, lock *flock.Flock) notify.Condition {
260262
return func(now time.Time) (deadline time.Time, callback func()) {
261263
// Keep trying to regain the lock.
262-
locked, err := lock.TryLockContext(ctx, autostopPollInterval)
264+
locked, err := lock.TryLockContext(ctx, workspacePollInterval)
263265
if err != nil || !locked {
264266
return time.Time{}, nil
265267
}

cryptorand/numbers.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cryptorand
33
import (
44
"crypto/rand"
55
"encoding/binary"
6+
"time"
67

78
"golang.org/x/xerrors"
89
)
@@ -193,3 +194,13 @@ func Bool() (bool, error) {
193194
// True if the least significant bit is 1
194195
return i&1 == 1, nil
195196
}
197+
198+
// Duration returns a random time.Duration value
199+
func Duration() (time.Duration, error) {
200+
i, err := Int63()
201+
if err != nil {
202+
return time.Duration(0), err
203+
}
204+
205+
return time.Duration(i), nil
206+
}

cryptorand/numbers_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,14 @@ func TestBool(t *testing.T) {
175175
require.True(t, percentage > 48, "expected more than 48 percent of values to be true")
176176
require.True(t, percentage < 52, "expected less than 52 percent of values to be true")
177177
}
178+
179+
func TestDuration(t *testing.T) {
180+
t.Parallel()
181+
182+
for i := 0; i < 20; i++ {
183+
v, err := cryptorand.Duration()
184+
require.NoError(t, err, "unexpected error from Duration")
185+
t.Logf("value: %v <- random?", v)
186+
require.True(t, v >= 0.0, "values must be positive")
187+
}
188+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy