···12131213 fs.IntVar(&rc.blockProfileRate, "block_profile_rate", getEnvWithDefaultInt("BLOCK_PROFILE_RATE", -1), "Sampling rate of Go's block profiler in nanoseconds. Values <=0 disable the blocking profiler Var(default). A value of 1 includes every blocking event. See https://pkg.go.dev/runtime#SetBlockProfileRate")
12141214 fs.DurationVar(&rc.backoffDuration, "backoff_duration", getEnvWithDefaultDuration("BACKOFF_DURATION", 10*time.Minute), "for the given duration we backoff from enqueue operations for a repository that's failed its previous indexing attempt. Consecutive failures increase the duration of the delay linearly up to the maxBackoffDuration. A negative value disables indexing backoff.")
12151215 fs.DurationVar(&rc.maxBackoffDuration, "max_backoff_duration", getEnvWithDefaultDuration("MAX_BACKOFF_DURATION", 120*time.Minute), "the maximum duration to backoff from enqueueing a repo for indexing. A negative value disables indexing backoff.")
12161216- fs.BoolVar(&rc.useGRPC, "use_grpc", getEnvWithDefaultBool("GRPC_ENABLED", false), "use the gRPC API to talk to Sourcegraph")
12161216+ fs.BoolVar(&rc.useGRPC, "use_grpc", mustGetBoolFromEnvironmentVariables([]string{"GRPC_ENABLED", "SG_FEATURE_FLAG_GRPC"}, true), "use the gRPC API to talk to Sourcegraph")
1217121712181218 // flags related to shard merging
12191219 fs.DurationVar(&rc.vacuumInterval, "vacuum_interval", getEnvWithDefaultDuration("SRC_VACUUM_INTERVAL", 24*time.Hour), "run vacuum this often")
···15961596 log.Fatal(err)
15971597 }
15981598}
15991599+16001600+// mustGetBoolFromEnvironmentVariables is like getBoolFromEnvironmentVariables, but it panics
16011601+// if any of the provided environment variables fails to parse as a boolean.
16021602+func mustGetBoolFromEnvironmentVariables(envVarNames []string, defaultBool bool) bool {
16031603+ value, err := getBoolFromEnvironmentVariables(envVarNames, defaultBool)
16041604+ if err != nil {
16051605+ panic(err)
16061606+ }
16071607+16081608+ return value
16091609+}
16101610+16111611+// getBoolFromEnvironmentVariables returns the boolean defined by the first environment
16121612+// variable listed in envVarNames that is set in the current process environment, or the defaultBool if none are set.
16131613+//
16141614+// An error is returned of the provided environment variables fails to parse as a boolean.
16151615+func getBoolFromEnvironmentVariables(envVarNames []string, defaultBool bool) (bool, error) {
16161616+ for _, envVar := range envVarNames {
16171617+ v := os.Getenv(envVar)
16181618+ if v == "" {
16191619+ continue
16201620+ }
16211621+16221622+ b, err := strconv.ParseBool(v)
16231623+ if err != nil {
16241624+ return false, fmt.Errorf("parsing environment variable %q to boolean: %v", envVar, err)
16251625+ }
16261626+16271627+ return b, nil
16281628+ }
16291629+16301630+ return defaultBool, nil
16311631+}
+97
cmd/zoekt-sourcegraph-indexserver/main_test.go
···286286 }
287287}
288288289289+func TestGetBoolFromEnvironmentVariables(t *testing.T) {
290290+ testCases := []struct {
291291+ name string
292292+ envVarsToSet map[string]string
293293+294294+ envVarNames []string
295295+ defaultBool bool
296296+297297+ wantBool bool
298298+ wantErr bool
299299+ }{
300300+ {
301301+ name: "respect default value: true",
302302+303303+ envVarsToSet: map[string]string{},
304304+305305+ envVarNames: []string{"FOO", "BAR"},
306306+ defaultBool: true,
307307+308308+ wantBool: true,
309309+ },
310310+ {
311311+ name: "respect default value: false",
312312+313313+ envVarsToSet: map[string]string{},
314314+315315+ envVarNames: []string{"FOO", "BAR"},
316316+ defaultBool: false,
317317+318318+ wantBool: false,
319319+ },
320320+ {
321321+ name: "read from environment",
322322+323323+ envVarsToSet: map[string]string{"FOO": "1"},
324324+325325+ envVarNames: []string{"FOO"},
326326+ defaultBool: false,
327327+328328+ wantBool: true,
329329+ },
330330+ {
331331+ name: "read from first env var that is set",
332332+333333+ envVarsToSet: map[string]string{
334334+ "BAR": "false",
335335+ "BAZ": "true",
336336+ },
337337+338338+ envVarNames: []string{"FOO", "BAR", "BAZ"},
339339+ defaultBool: true,
340340+341341+ wantBool: false,
342342+ },
343343+344344+ {
345345+ name: "should error for invalid input",
346346+347347+ envVarsToSet: map[string]string{"INVALID": "not a boolean"},
348348+349349+ envVarNames: []string{"INVALID"},
350350+ defaultBool: false,
351351+352352+ wantErr: true,
353353+ },
354354+ }
355355+356356+ for _, tc := range testCases {
357357+ t.Run("", func(t *testing.T) {
358358+ // Prepare the environment by loading all the appropriate environment variables
359359+ for _, v := range tc.envVarNames {
360360+ _ = os.Unsetenv(v)
361361+ }
362362+363363+ for k, _ := range tc.envVarsToSet {
364364+ _ = os.Unsetenv(k)
365365+ }
366366+367367+ for k, v := range tc.envVarsToSet {
368368+ t.Setenv(k, v)
369369+ }
370370+371371+ // Run the test
372372+ got, err := getBoolFromEnvironmentVariables(tc.envVarNames, tc.defaultBool)
373373+374374+ // Examine the results
375375+ if tc.wantErr != (err != nil) {
376376+ t.Fatalf("unexpected error (wantErr = %t): %v", tc.wantErr, err)
377377+ }
378378+379379+ if got != tc.wantBool {
380380+ t.Errorf("got %v, want %v", got, tc.wantBool)
381381+ }
382382+ })
383383+ }
384384+}
385385+289386func TestAddDefaultPort(t *testing.T) {
290387 tests := []struct {
291388 name string