Skip to content

Commit 965b42e

Browse files
authored
Allow selecting enabled worker languages (#309)
1 parent 9c2c444 commit 965b42e

5 files changed

Lines changed: 109 additions & 3 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ The control microservice is the server that receives requests from the user. It
4545
### Worker
4646

4747
For each of the languages, there are individual Docker images and worker implementations since each language gets executed differently.
48+
The control service enables all supported languages by default. Set the
49+
comma-separated `WORKER_LANGUAGES` environment variable before generating the
50+
Kubernetes manifests to run only a subset, for example `javascript,python`.
4851

4952
## Generate / Update autocompletion
5053

‎control-service/main.go‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,12 @@ func newServer() (*server, error) {
104104
}
105105
}
106106

107+
workerLanguages, err := parseWorkerLanguages(os.Getenv("WORKER_LANGUAGES"))
108+
if err != nil {
109+
return nil, err
110+
}
107111
workersMap := map[workertypes.WorkerLanguage]*Workers{}
108-
for _, lang := range workertypes.SUPPORTED_LANGUAGES {
112+
for _, lang := range workerLanguages {
109113
workersMap[lang], err = newWorkers(lang, workerCount, k8ClientSet, amqpChannel)
110114
if err != nil {
111115
return nil, fmt.Errorf("could not create new %s workers: %w", lang, err)
@@ -186,6 +190,10 @@ func (s *server) handleRun(c *echo.Context) error {
186190
if !req.Language.IsValid() {
187191
return respondError(c, http.StatusBadRequest, requestID, testID, logBuffer, "could not recognize language")
188192
}
193+
workers, enabled := s.workers[req.Language]
194+
if !enabled {
195+
return respondError(c, http.StatusBadRequest, requestID, testID, logBuffer, "language is not enabled")
196+
}
189197

190198
logger.Printf("Validating turnstile")
191199
if err := ValidateTurnstile(c.Request().Context(), req.Token, getTurnstileIP(c), os.Getenv("TURNSTILE_SECRET_KEY")); err != nil {
@@ -197,7 +205,7 @@ func (s *server) handleRun(c *echo.Context) error {
197205
logger.Printf("Obtaining worker")
198206
var worker *Worker
199207
select {
200-
case worker = <-s.workers[req.Language].GetCh():
208+
case worker = <-workers.GetCh():
201209
case <-time.After(WORKER_TIMEOUT * time.Second):
202210
logger.Println("Got Worker timeout, was not able to get a worker!")
203211
return respondError(c, http.StatusServiceUnavailable, requestID, testID, logBuffer, "Timeout in getting a worker!")
@@ -238,7 +246,7 @@ func (s *server) handleRun(c *echo.Context) error {
238246
logger.Println("Finished worker cleanup")
239247

240248
logger.Println("Adding new worker")
241-
if err := s.workers[req.Language].AddWorkers(1); err != nil {
249+
if err := workers.AddWorkers(1); err != nil {
242250
logger.Printf("could not create new worker: %v", err)
243251
return
244252
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/mxschmitt/try-playwright/internal/workertypes"
8+
)
9+
10+
func parseWorkerLanguages(value string) ([]workertypes.WorkerLanguage, error) {
11+
if strings.TrimSpace(value) == "" {
12+
return append([]workertypes.WorkerLanguage(nil), workertypes.SUPPORTED_LANGUAGES...), nil
13+
}
14+
15+
languages := make([]workertypes.WorkerLanguage, 0)
16+
seen := map[workertypes.WorkerLanguage]bool{}
17+
for _, item := range strings.Split(value, ",") {
18+
language := workertypes.WorkerLanguage(strings.TrimSpace(item))
19+
if !language.IsValid() {
20+
return nil, fmt.Errorf("invalid language in 'WORKER_LANGUAGES': %q", language)
21+
}
22+
if seen[language] {
23+
return nil, fmt.Errorf("duplicate language in 'WORKER_LANGUAGES': %q", language)
24+
}
25+
seen[language] = true
26+
languages = append(languages, language)
27+
}
28+
return languages, nil
29+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package main
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/mxschmitt/try-playwright/internal/workertypes"
8+
)
9+
10+
func TestParseWorkerLanguages(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
value string
14+
want []workertypes.WorkerLanguage
15+
wantErr bool
16+
}{
17+
{
18+
name: "defaults to all supported languages",
19+
value: "",
20+
want: workertypes.SUPPORTED_LANGUAGES,
21+
},
22+
{
23+
name: "selects one language",
24+
value: "javascript",
25+
want: []workertypes.WorkerLanguage{workertypes.WorkerLanguageJavaScript},
26+
},
27+
{
28+
name: "trims comma-separated languages",
29+
value: " python, java ",
30+
want: []workertypes.WorkerLanguage{
31+
workertypes.WorkerLanguagePython,
32+
workertypes.WorkerLanguageJava,
33+
},
34+
},
35+
{
36+
name: "rejects an unsupported language",
37+
value: "javascript,ruby",
38+
wantErr: true,
39+
},
40+
{
41+
name: "rejects a duplicate language",
42+
value: "javascript,javascript",
43+
wantErr: true,
44+
},
45+
}
46+
47+
for _, test := range tests {
48+
t.Run(test.name, func(t *testing.T) {
49+
got, err := parseWorkerLanguages(test.value)
50+
if test.wantErr {
51+
if err == nil {
52+
t.Fatal("parseWorkerLanguages() did not return an error")
53+
}
54+
return
55+
}
56+
if err != nil {
57+
t.Fatalf("parseWorkerLanguages() returned an error: %v", err)
58+
}
59+
if !reflect.DeepEqual(got, test.want) {
60+
t.Fatalf("parseWorkerLanguages() = %v, want %v", got, test.want)
61+
}
62+
})
63+
}
64+
}

‎k8/control-deployment.yaml.tpl‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ spec:
1919
- env:
2020
- name: WORKER_COUNT
2121
value: "${WORKER_COUNT}"
22+
- name: WORKER_LANGUAGES
23+
value: "${WORKER_LANGUAGES}"
2224
- name: CONTROL_HTTP_PORT
2325
value: "8080"
2426
- name: ETCD_ENDPOINT

0 commit comments

Comments
 (0)