diff --git a/.github/workflows/airflow-operator.yml b/.github/workflows/airflow-operator.yml index cc4704cfa56..50747f98dc7 100644 --- a/.github/workflows/airflow-operator.yml +++ b/.github/workflows/airflow-operator.yml @@ -13,9 +13,7 @@ on: - 'client/python/**' - 'docs/python_airflow_operator.md' - 'docs/python_armada_client.md' - - 'internal/jobservice/*' - 'pkg/api/*.proto' - - 'pkg/api/jobservice/*.proto' - 'scripts/build-python-client.sh' - 'third_party/airflow/**' - './magefiles/tests.go' @@ -33,9 +31,7 @@ on: - 'client/python/**' - 'docs/python_airflow_operator.md' - 'docs/python_armada_client.md' - - 'internal/jobservice/*' - 'pkg/api/*.proto' - - 'pkg/api/jobservice/*.proto' - 'scripts/build-python-client.sh' - 'third_party/airflow/**' diff --git a/.gitignore b/.gitignore index 806150767e9..73c5e2d5452 100644 --- a/.gitignore +++ b/.gitignore @@ -9,10 +9,6 @@ armadactl.yaml loadtest.yaml test_reports code_reports -/jobservice -jobservice.db -jobservice.db-shm -jobservice.db-wal /armadactl junit.xml docker-compose.dev.yaml diff --git a/.goreleaser.yml b/.goreleaser.yml index 251fe7001da..a6869530018 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -112,15 +112,6 @@ builds: - linux goarch: - amd64 - - env: [CGO_ENABLED=0] - id: jobservice - binary: jobservice - main: ./cmd/jobservice/main.go - mod_timestamp: '{{ .CommitTimestamp }}' - goos: - - linux - goarch: - - amd64 - env: [CGO_ENABLED=0] id: fakeexecutor binary: fakeexecutor @@ -246,7 +237,6 @@ dockers: - executor - binoculars - eventingester - - jobservice - armadactl - scheduler - scheduleringester @@ -262,7 +252,6 @@ dockers: - config/scheduleringester/config.yaml - config/lookoutv2/config.yaml - config/lookoutingesterv2/config.yaml - - config/jobservice/config.yaml - internal/lookout/ui - pkg/api/api.swagger.json - pkg/api/binoculars/api.swagger.json @@ -423,20 +412,6 @@ dockers: - config/binoculars/config.yaml dockerfile: ./build_goreleaser/binoculars/Dockerfile - - id: jobservice - use: buildx - goos: linux - goarch: amd64 - image_templates: - - "{{ .Env.DOCKER_REPO }}armada-jobservice:latest" - - "{{ .Env.DOCKER_REPO }}armada-jobservice:{{ .Version }}" - build_flag_templates: *BUILD_FLAG_TEMPLATES - ids: - - jobservice - extra_files: - - config/jobservice/config.yaml - dockerfile: ./build_goreleaser/jobservice/Dockerfile - - id: armadactl use: buildx goos: linux @@ -528,9 +503,6 @@ release: #### Armada Binoculars - `docker pull {{ .Env.DOCKER_REPO }}armada-binoculars:{{ .Version }}` - `docker pull {{ .Env.DOCKER_REPO }}armada-binoculars:latest` - #### Armada Job Service - - `docker pull {{ .Env.DOCKER_REPO }}armada-jobservice:{{ .Version }}` - - `docker pull {{ .Env.DOCKER_REPO }}armada-jobservice:latest` #### armadactl - `docker pull {{ .Env.DOCKER_REPO }}armadactl:{{ .Version }}` - `docker pull {{ .Env.DOCKER_REPO }}armadactl:latest` diff --git a/build/jobservice/Dockerfile b/build/jobservice/Dockerfile deleted file mode 100644 index b9340243bfd..00000000000 --- a/build/jobservice/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM alpine:3.20.1 - -RUN addgroup -S -g 2000 armada && adduser -S -u 1000 armada -G armada - -USER armada - -COPY ./jobservice /app/ - -COPY ./config/ /app/config/jobservice - - -WORKDIR /app - -ENTRYPOINT ["./jobservice", "run"] diff --git a/build_goreleaser/bundles/full/Dockerfile b/build_goreleaser/bundles/full/Dockerfile index a1e4ec658ae..920284f849e 100644 --- a/build_goreleaser/bundles/full/Dockerfile +++ b/build_goreleaser/bundles/full/Dockerfile @@ -22,7 +22,7 @@ RUN addgroup -S -g 2000 armada && adduser -S -u 1000 armada -G armada USER armada COPY --from=NODE /ui/build/ /app/internal/lookout/ui/build -COPY server executor binoculars eventingester lookoutingesterv2 lookoutv2 jobservice scheduler scheduleringester armadactl /app/ +COPY server executor binoculars eventingester lookoutingesterv2 lookoutv2 scheduler scheduleringester armadactl /app/ COPY config/ /app/config/ WORKDIR /app diff --git a/build_goreleaser/jobservice/Dockerfile b/build_goreleaser/jobservice/Dockerfile deleted file mode 100644 index cb1540bbb7a..00000000000 --- a/build_goreleaser/jobservice/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -ARG BASE_IMAGE=alpine:3.20.1 - -FROM ${BASE_IMAGE} -LABEL org.opencontainers.image.title=jobservice -LABEL org.opencontainers.image.description="Job Service" -LABEL org.opencontainers.image.url=https://hub.docker.com/r/gresearchdev/jobservice - -RUN addgroup -S -g 2000 armada && adduser -S -u 1000 armada -G armada -USER armada - -COPY jobservice /app/ -COPY config/jobservice/config.yaml /app/config/jobservice/config.yaml - -WORKDIR /app - -ENTRYPOINT ["./jobservice", "run"] diff --git a/client/python/examples/general.py b/client/python/examples/general.py index d4a6de96a5e..aed3421e3ca 100644 --- a/client/python/examples/general.py +++ b/client/python/examples/general.py @@ -53,8 +53,6 @@ def wait_for_job_event(client, event_stream, job_id: str, event_state: EventType Wait for a job event to occur. Will automatically return if the event is considered terminal. - A list of terminal events can be found here: - https://github.com/armadaproject/armada/blob/master/internal/jobservice/eventstojobs/event_job_response_test.go Please note that this is shown for demonstration purposes only. Subscribing to events like this to watch individual events like diff --git a/cmd/jobservice/cmd/root.go b/cmd/jobservice/cmd/root.go deleted file mode 100644 index 9ea595e3d0b..00000000000 --- a/cmd/jobservice/cmd/root.go +++ /dev/null @@ -1,25 +0,0 @@ -package cmd - -import ( - "github.com/spf13/cobra" - - "github.com/armadaproject/armada/internal/common" - "github.com/armadaproject/armada/internal/jobservice" -) - -// RootCmd is the root Cobra command that gets called from the main func. -// All other sub-commands should be registered here. -func RootCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "jobservice", - Short: "jobservice is used for polling functionality", - } - common.ConfigureLogging() - common.BindCommandlineArguments() - - cmd.AddCommand( - runCmd(jobservice.New()), - ) - - return cmd -} diff --git a/cmd/jobservice/cmd/run.go b/cmd/jobservice/cmd/run.go deleted file mode 100644 index 5a8f19831ea..00000000000 --- a/cmd/jobservice/cmd/run.go +++ /dev/null @@ -1,66 +0,0 @@ -package cmd - -import ( - "context" - "fmt" - "os" - "os/signal" - "strings" - "syscall" - - log "github.com/sirupsen/logrus" - - "github.com/spf13/cobra" - "golang.org/x/sync/errgroup" - - "github.com/armadaproject/armada/internal/common" - "github.com/armadaproject/armada/internal/jobservice" - "github.com/armadaproject/armada/internal/jobservice/configuration" -) - -func runCmd(app *jobservice.App) *cobra.Command { - cmd := &cobra.Command{ - Use: "run", - RunE: runCmdE(app), - } - - cmd.Flags().String("config", "", "Configuration") - - return cmd -} - -func runCmdE(app *jobservice.App) func(cmd *cobra.Command, args []string) error { - return func(cmd *cobra.Command, args []string) error { - g, ctx := errgroup.WithContext(context.Background()) - var config configuration.JobServiceConfiguration - - configValue, configErr := cmd.Flags().GetString("config") - if configErr != nil { - log.Warnf("error parsing config in startup %v", configErr) - } - configArray := strings.Split(configValue, " ") - common.LoadConfig(&config, "./config/jobservice", configArray) - - err := app.StartUp(ctx, &config) - if err != nil { - panic(err) - } - - // Cancel the errgroup context on SIGINT and SIGTERM, - // which shuts everything down gracefully. - stopSignal := make(chan os.Signal, 1) - signal.Notify(stopSignal, syscall.SIGINT, syscall.SIGTERM) - g.Go(func() error { - select { - case <-ctx.Done(): - return ctx.Err() - case sig := <-stopSignal: - if err := ctx.Err(); err != nil { - log.Warnf("error from stopping %v", err) - } - return fmt.Errorf("received signal %v", sig) - } - }) - return g.Wait() - } -} diff --git a/cmd/jobservice/main.go b/cmd/jobservice/main.go deleted file mode 100644 index 55e73116e46..00000000000 --- a/cmd/jobservice/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - log "github.com/sirupsen/logrus" - - "github.com/armadaproject/armada/cmd/jobservice/cmd" - "github.com/armadaproject/armada/internal/common" -) - -func main() { - common.ConfigureCommandLineLogging() - root := cmd.RootCmd() - if err := root.Execute(); err != nil { - log.Fatal(err) - } -} diff --git a/config/jobservice/config.yaml b/config/jobservice/config.yaml deleted file mode 100644 index 58a6bd8e72d..00000000000 --- a/config/jobservice/config.yaml +++ /dev/null @@ -1,42 +0,0 @@ -grpcPort: 60003 -httpPort: 8090 -purgeJobSetTime: 1000 -subscriptionExpirySecs: 300 -subscriberPoolSize: 30 -# databaseType can be either 'postgres' or 'sqlite' -databaseType: "postgres" -# databasePath specifies the location of the back-end -# storage file when using database type 'sqlite' -databasePath: "/var/jobservice.db" -# Connection details when using database type 'postgres' -postgresConfig: - poolMaxConns: 50 - poolMinConns: 10 - poolMaxConnLifetime: 30m - connection: - host: postgres - port: 5432 - user: postgres - password: psw - dbname: postgres - sslmode: disable -grpc: - keepaliveParams: - maxConnectionIdle: 5m - time: 2h - timeout: 20s - keepaliveEnforcementPolicy: - minTime: 5m - permitWithoutStream: false - tls: - enabled: false -# gRPC connection pool to armada server configuration. -grpcPool: - initialConnections: 5 - capacity: 5 -# These connections can be used in production if not explicity overridden. -# Do not add ForceNoTls as that can cause silent failures -# If you want that for local testing, then use an override. -apiConnection: - armadaUrl: "server:50051" - forceNoTls: true diff --git a/deployment/jobservice/Chart.yaml b/deployment/jobservice/Chart.yaml deleted file mode 100644 index 8f2a4d22a8d..00000000000 --- a/deployment/jobservice/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -description: A helm chart for armada-jobservice component -name: armada-jobservice -version: 0.0.0-latest -appVersion: 0.0.0-latest diff --git a/deployment/jobservice/README.md b/deployment/jobservice/README.md deleted file mode 100644 index e093ed458a5..00000000000 --- a/deployment/jobservice/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# armada-jobservice - -![Version: 0.0.0-latest](https://img.shields.io/badge/Version-0.0.0--latest-informational?style=flat-square) ![AppVersion: 0.0.0-latest](https://img.shields.io/badge/AppVersion-0.0.0--latest-informational?style=flat-square) - -A helm chart for armada-jobservice component - -## Values - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| additionalLabels | object | `{}` | | -| applicationConfig.grpcPort | int | `60063` | | -| customServiceAccount | string | `nil` | | -| image.repository | string | `"gresearchdev/armada-server"` | | -| image.tag | string | `"0.0.0-latest"` | | -| ingress.annotations | object | `{}` | | -| ingress.labels | object | `{}` | | -| ingress.nameOverride | string | `""` | | -| prometheus.enabled | bool | `false` | | -| prometheus.labels | object | `{}` | | -| prometheus.scrapeInterval | string | `"10s"` | | -| replicas | int | `1` | | -| resources.limits.cpu | string | `"300m"` | | -| resources.limits.memory | string | `"1Gi"` | | -| resources.requests.cpu | string | `"200m"` | | -| resources.requests.memory | string | `"512Mi"` | | -| serviceAccount | string | `nil` | | -| strategy.rollingUpdate.maxUnavailable | int | `1` | | -| strategy.type | string | `"RollingUpdate"` | | -| terminationGracePeriodSeconds | int | `30` | | - ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/deployment/jobservice/templates/_helpers.tpl b/deployment/jobservice/templates/_helpers.tpl deleted file mode 100644 index d2cc0a23352..00000000000 --- a/deployment/jobservice/templates/_helpers.tpl +++ /dev/null @@ -1,43 +0,0 @@ - -{{- define "jobservice.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{- define "jobservice.config.name" -}} -{{- printf "%s-%s" ( include "jobservice.name" .) "config" -}} -{{- end }} - -{{- define "jobservice.config.filename" -}} -{{- printf "%s%s" ( include "jobservice.config.name" .) ".yaml" -}} -{{- end }} - -{{- define "jobservice.users.name" -}} -{{- printf "%s-%s" ( include "jobservice.name" .) "users" -}} -{{- end }} - -{{- define "jobservice.users.filename" -}} -{{- printf "%s%s" ( include "jobservice.users.name" .) ".yaml" -}} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "jobservice.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{- define "jobservice.labels.identity" -}} -app: {{ include "jobservice.name" . }} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "jobservice.labels.all" -}} -{{ include "jobservice.labels.identity" . }} -chart: {{ include "jobservice.chart" . }} -release: {{ .Release.Name }} -{{- if .Values.additionalLabels }} -{{ toYaml .Values.additionalLabels }} -{{- end }} -{{- end -}} diff --git a/deployment/jobservice/templates/ingress.yaml b/deployment/jobservice/templates/ingress.yaml deleted file mode 100644 index f9afb708b64..00000000000 --- a/deployment/jobservice/templates/ingress.yaml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ .Values.ingress.nameOverride | default (include "jobservice.name" .) }} - namespace: {{ .Release.Namespace }} - annotations: - kubernetes.io/ingress.class: {{ required "A value is required for .Values.ingressClass" .Values.ingressClass }} - nginx.ingress.kubernetes.io/ssl-redirect: "true" - {{- if .Values.applicationConfig.grpc.tls.enabled }} - nginx.ingress.kubernetes.io/backend-protocol: "GRPCS" - nginx.ingress.kubernetes.io/ssl-passthrough: "true" - {{- else }} - nginx.ingress.kubernetes.io/backend-protocol: "GRPC" - {{- end }} - certmanager.k8s.io/cluster-issuer: {{ required "A value is required for .Values.clusterIssuer" .Values.clusterIssuer }} - cert-manager.io/cluster-issuer: {{ required "A value is required for .Values.clusterIssuer" .Values.clusterIssuer }} - {{- if .Values.ingress.annotations }} - {{- toYaml .Values.ingress.annotations | nindent 4 }} - {{- end }} - labels: - {{- include "jobservice.labels.all" . | nindent 4 }} - {{- if .Values.ingress.labels }} - {{- toYaml .Values.ingress.labels | nindent 4 }} - {{- end }} -spec: - rules: - {{- $root := . -}} - {{ range required "A value is required for .Values.hostnames" .Values.hostnames }} - - host: {{ . }} - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ include "jobservice.name" $root }} - port: - number: {{ $root.Values.applicationConfig.grpcPort }} - {{ end }} - tls: - - hosts: - {{- toYaml .Values.hostnames | nindent 8 }} - secretName: jobservice-service-tls diff --git a/deployment/jobservice/templates/secret.yaml b/deployment/jobservice/templates/secret.yaml deleted file mode 100644 index c3c8c3614a5..00000000000 --- a/deployment/jobservice/templates/secret.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "jobservice.config.name" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "jobservice.labels.all" . | nindent 4 }} -type: Opaque -data: - {{ include "jobservice.config.filename" . }}: | - {{- if .Values.applicationConfig }} - {{ toYaml .Values.applicationConfig | b64enc | indent 4 }} - {{- end }} diff --git a/deployment/jobservice/templates/service.yaml b/deployment/jobservice/templates/service.yaml deleted file mode 100644 index 83d07a25bc7..00000000000 --- a/deployment/jobservice/templates/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "jobservice.name" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "jobservice.labels.all" . | nindent 4 }} -spec: - {{- if .Values.nodePort }} - type: NodePort - {{- end }} - selector: - {{- include "jobservice.labels.identity" . | nindent 4 }} - ports: - - name: grpc - protocol: TCP - port: {{ .Values.applicationConfig.grpcPort }} - {{- if .Values.nodePort }} - nodePort: {{ .Values.nodePort }} - {{- end }} diff --git a/deployment/jobservice/templates/serviceaccount.yaml b/deployment/jobservice/templates/serviceaccount.yaml deleted file mode 100644 index f0c09af70c0..00000000000 --- a/deployment/jobservice/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{ if not .Values.customServiceAccount }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "jobservice.name" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "jobservice.labels.all" . | nindent 4 }} - {{ if .Values.serviceAccount }} - {{ toYaml .Values.serviceAccount }} - {{ end }} -{{ end }} diff --git a/deployment/jobservice/templates/statefulset.yaml b/deployment/jobservice/templates/statefulset.yaml deleted file mode 100644 index 2519f1b69c0..00000000000 --- a/deployment/jobservice/templates/statefulset.yaml +++ /dev/null @@ -1,86 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ include "jobservice.name" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "jobservice.labels.all" . | nindent 4 }} -spec: - replicas: 1 - serviceName: {{ include "jobservice.name" . }} - selector: - matchLabels: - {{- include "jobservice.labels.identity" . | nindent 6 }} - template: - metadata: - name: {{ include "jobservice.name" . }} - labels: - {{- include "jobservice.labels.all" . | nindent 8 }} - spec: - terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} - serviceAccountName: {{ .Values.customServiceAccount | default (include "jobservice.name" .) }} - securityContext: - runAsUser: 1000 - runAsGroup: 2000 - {{- if .Values.tolerations }} - tolerations: - {{- toYaml .Values.tolerations | nindent 8 }} - {{- end }} - containers: - - name: jobservice - imagePullPolicy: IfNotPresent - image: {{ .Values.image.repository }}:{{ required "A value is required for .Values.image.tag" .Values.image.tag }} - args: - - run - - --config - - /config/application_config.yaml - {{- if .Values.env }} - env: - {{- toYaml .Values.env | nindent 12 -}} - {{- end }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - ports: - - containerPort: {{ .Values.applicationConfig.grpcPort }} - protocol: TCP - name: grpc - volumeMounts: - - name: user-config - mountPath: /config/application_config.yaml - subPath: {{ include "jobservice.config.filename" . }} - readOnly: true - {{- if .Values.applicationConfig.grpc.tls.enabled }} - - name: tls-certs - mountPath: /certs - readOnly: true - {{- end }} - {{- if .Values.additionalVolumeMounts }} - {{- toYaml .Values.additionalVolumeMounts | nindent 12 -}} - {{- end }} - - securityContext: - allowPrivilegeEscalation: false - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - labelSelector: - matchExpressions: - - key: app - operator: In - values: - - {{ include "jobservice.name" . }} - topologyKey: kubernetes.io/hostname - volumes: - - name: user-config - secret: - secretName: {{ include "jobservice.config.name" . }} - {{- if .Values.applicationConfig.grpc.tls.enabled }} - - name: tls-certs - secret: - secretName: jobservice-service-tls - {{- end }} - {{- if .Values.additionalVolumes }} - {{- toYaml .Values.additionalVolumes | nindent 8 }} - {{- end }} diff --git a/deployment/jobservice/values.yaml b/deployment/jobservice/values.yaml deleted file mode 100644 index 27ce94010b2..00000000000 --- a/deployment/jobservice/values.yaml +++ /dev/null @@ -1,37 +0,0 @@ -image: - repository: gresearchdev/armada-server - tag: 0.0.0-latest -resources: - limits: - memory: 1Gi - cpu: 300m - requests: - memory: 512Mi - cpu: 200m -# -- Tolerations -tolerations: [] -additionalLabels: {} -terminationGracePeriodSeconds: 30 -replicas: 1 -strategy: - rollingUpdate: - maxUnavailable: 1 - type: RollingUpdate -ingress: - nameOverride: "" - annotations: {} - labels: {} -prometheus: - enabled: false - labels: {} - scrapeInterval: 10s -customServiceAccount: null -serviceAccount: null - -applicationConfig: - grpcPort: 60063 - grpc: - tls: - enabled: false - certPath: /certs/tls.crt - keyPath: /certs/tls.key diff --git a/developer/dependencies/airflow-start.sh b/developer/dependencies/airflow-start.sh index 59d9c44f4d2..054efdb74f6 100644 --- a/developer/dependencies/airflow-start.sh +++ b/developer/dependencies/airflow-start.sh @@ -7,7 +7,6 @@ export AIRFLOW_HOME=~/airflow mkdir -p ~/airflow/dags cp ./third_party/airflow/examples/* ~/airflow/dags sed -i 's/127.0.0.1:50051/server:50051/g' ~/airflow/dags/*.py -sed -i 's/127.0.0.1:60003/jobservice:60003/g' ~/airflow/dags/*.py sed -i 's/127.0.0.1:8089/lookout:8089/g' ~/airflow/dags/*.py sed -i 's/test/queue-a/g' ~/airflow/dags/*.py @@ -20,4 +19,4 @@ airflow users create --role Admin --username admin --email admin --firstname ad airflow webserver -p 8081 & # Run the scheduler -airflow scheduler \ No newline at end of file +airflow scheduler diff --git a/developer/dependencies/postgres-init.sh b/developer/dependencies/postgres-init.sh index 92e5589ee8f..40eb6e2d56e 100755 --- a/developer/dependencies/postgres-init.sh +++ b/developer/dependencies/postgres-init.sh @@ -5,8 +5,6 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E CREATE USER docker; CREATE DATABASE lookout; GRANT ALL PRIVILEGES ON DATABASE lookout TO docker; - CREATE DATABASE jobservice; - GRANT ALL PRIVILEGES ON DATABASE jobservice TO docker; CREATE DATABASE scheduler; GRANT ALL PRIVILEGES ON DATABASE scheduler TO docker; EOSQL diff --git a/developer/env/docker/jobservice.env b/developer/env/docker/jobservice.env deleted file mode 100644 index 4a94b780091..00000000000 --- a/developer/env/docker/jobservice.env +++ /dev/null @@ -1,2 +0,0 @@ -ARMADA_DATABASEPATH="/tmp/jobservice.db" -JOBSERVICE_DEBUG="1" diff --git a/developer/env/local/jobservice.env b/developer/env/local/jobservice.env deleted file mode 100644 index b1ea329eefa..00000000000 --- a/developer/env/local/jobservice.env +++ /dev/null @@ -1,4 +0,0 @@ -ARMADA_DATABASEPATH="/tmp/jobservice.db" -JOBSERVICE_DEBUG="1" -ARMADA_POSTGRESCONFIG_CONNECTION_HOST=localhost -ARMADA_APICONNECTION_ARMADAURL="localhost:50051" diff --git a/docker-compose.yaml b/docker-compose.yaml index 68af1ce7aa2..748da9306d3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -217,24 +217,6 @@ services: working_dir: /app command: ./lookoutingesterv2 - jobservice: - container_name: jobservice - image: ${ARMADA_IMAGE:-gresearch/armada-jobservice}:${ARMADA_IMAGE_TAG:-latest} - volumes: - - "go-cache:/root/.cache/go-build:rw" - - "gomod-cache:/go/pkg/mod:rw" - networks: - - kind - ports: - - 60003:60003 - - 4008:4000 - depends_on: - - server - env_file: - - ./developer/env/docker/jobservice.env - working_dir: /app - command: ./jobservice run - airflow: container_name: airflow image: python:3.8-buster diff --git a/docs/developer.md b/docs/developer.md index afde2ceee8a..8e2f5b4a8c8 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -227,7 +227,6 @@ External Debug Port Mappings: |lookoutv2 |localhost:4005| |lookoutingester |localhost:4006| |lookoutingesterv2 |localhost:4007| -|jobservice |localhost:4008| ## GoLand Run Configurations diff --git a/docs/python_airflow_operator.md b/docs/python_airflow_operator.md index 665d6c0e82c..227dfeaa1b1 100644 --- a/docs/python_airflow_operator.md +++ b/docs/python_airflow_operator.md @@ -170,10 +170,162 @@ acknowledged by Armada. :type job_acknowledgement_timeout: int :param kwargs: Additional keyword arguments to pass to the BaseOperator. -## armada.operators.armada_deferrable module +## armada.triggers.armada module -## armada.operators.jobservice module -## armada.operators.jobservice_asyncio module +### _class_ armada.triggers.armada.ArmadaTrigger(job_id, armada_queue, job_set_id, poll_interval, tracking_message, job_acknowledgement_timeout, job_request_namespace, channel_args=None, channel_args_details=None, container_logs=None, k8s_token_retriever=None, k8s_token_retriever_details=None, last_log_time=None) +Bases: `BaseTrigger` -## armada.operators.utils module +An Airflow Trigger that can asynchronously manage an Armada job. + + +* **Parameters** + + + * **job_id** (*str*) – + + + * **armada_queue** (*str*) – + + + * **job_set_id** (*str*) – + + + * **poll_interval** (*int*) – + + + * **tracking_message** (*str*) – + + + * **job_acknowledgement_timeout** (*int*) – + + + * **job_request_namespace** (*str*) – + + + * **channel_args** (*GrpcChannelArgs*) – + + + * **channel_args_details** (*Dict**[**str**, **Any**]*) – + + + * **container_logs** (*str** | **None*) – + + + * **k8s_token_retriever** (*TokenRetriever** | **None*) – + + + * **k8s_token_retriever_details** (*Tuple**[**str**, **Dict**[**str**, **Any**]**] **| **None*) – + + + * **last_log_time** (*DateTime** | **None*) – + + + +#### _property_ client(_: ArmadaAsyncIOClien_ ) + +#### pod_manager(k8s_context) + +* **Parameters** + + **k8s_context** (*str*) – + + + +* **Return type** + + *PodLogManagerAsync* + + + +#### _async_ run() +Run the Trigger Asynchronously. This will poll Armada until the Job reaches a +terminal state + + +* **Return type** + + *AsyncIterator*[*TriggerEvent*] + + + +#### serialize() +Serialises the state of this Trigger. +When the Trigger is re-hydrated, these values will be passed to init() as kwargs +:return: + + +* **Return type** + + tuple + + +## armada.auth module + + +### _class_ armada.auth.TokenRetriever(\*args, \*\*kwargs) +Bases: `Protocol` + + +#### get_token() + +* **Return type** + + str + + + +#### serialize() + +* **Return type** + + *Tuple*[str, *Dict*[str, *Any*]] + + +## armada.model module + + +### _class_ armada.model.GrpcChannelArgs(target, options=None, compression=None, auth=None, auth_details=None) +Bases: `object` + + +* **Parameters** + + + * **target** (*str*) – + + + * **options** (*Sequence**[**Tuple**[**str**, **Any**]**] **| **None*) – + + + * **compression** (*Compression** | **None*) – + + + * **auth** (*AuthMetadataPlugin** | **None*) – + + + * **auth_details** (*Dict**[**str**, **Any**] **| **None*) – + + + +#### aio_channel() + +* **Return type** + + *Channel* + + + +#### channel() + +* **Return type** + + *Channel* + + + +#### serialize() + +* **Return type** + + *Dict*[str, *Any*] diff --git a/e2e/setup/jobservice.yaml b/e2e/setup/jobservice.yaml deleted file mode 100644 index dc8d713a624..00000000000 --- a/e2e/setup/jobservice.yaml +++ /dev/null @@ -1,22 +0,0 @@ -subscriptionExpirySecs: 60 -subscriberPoolSize: 30 -purgeJobSetTime: 10000 -databaseType: "postgres" -postgresConfig: - maxOpenConns: 50 - maxIdleConns: 10 - connMaxLifetime: 30m - connection: - host: postgres - port: 5432 - user: postgres - password: psw - dbname: jobservice - sslmode: disable -grpcPool: - initialConnections: 5 - capacity: 5 -apiConnection: - armadaUrl: "server:50051" - forceNoTls: true - diff --git a/go.mod b/go.mod index e366284c638..6b14f5dba64 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ replace github.com/AthenZ/athenz v1.10.39 => github.com/AthenZ/athenz v1.10.4 require ( github.com/apache/pulsar-client-go v0.11.0 github.com/coreos/go-oidc v2.2.1+incompatible - github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f github.com/go-openapi/analysis v0.22.2 github.com/go-openapi/jsonreference v0.20.4 github.com/go-openapi/loads v0.21.5 @@ -49,7 +48,6 @@ require ( golang.org/x/net v0.22.0 golang.org/x/oauth2 v0.18.0 golang.org/x/sync v0.6.0 - golang.org/x/tools v0.18.0 // indirect google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/grpc v1.59.0 gopkg.in/yaml.v2 v2.4.0 @@ -60,7 +58,6 @@ require ( k8s.io/kubectl v0.26.15 k8s.io/kubelet v0.26.15 k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 - modernc.org/sqlite v1.26.0 sigs.k8s.io/yaml v1.4.0 ) @@ -117,7 +114,6 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dlclark/regexp2 v1.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/elliotchance/orderedmap/v2 v2.2.0 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect @@ -158,7 +154,6 @@ require ( github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.17.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect @@ -187,7 +182,6 @@ require ( github.com/pquerna/cachecontrol v0.1.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.2 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -223,15 +217,6 @@ require ( k8s.io/cli-runtime v0.26.15 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect - lukechampine.com/uint128 v1.2.0 // indirect - modernc.org/cc/v3 v3.40.0 // indirect - modernc.org/ccgo/v3 v3.16.13 // indirect - modernc.org/libc v1.24.1 // indirect - modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.6.0 // indirect - modernc.org/opt v0.1.3 // indirect - modernc.org/strutil v1.1.3 // indirect - modernc.org/token v1.0.1 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/kustomize/api v0.12.1 // indirect sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect diff --git a/go.sum b/go.sum index bef3ddd75a7..2ac127d83c6 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/colinmarc/hdfs/v2 v2.1.1/go.mod h1:M3x+k8UKKmxtFu++uAZ0OtDU8jR3jnaZIAc6yK4Ue0c= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= @@ -119,8 +117,6 @@ github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk= @@ -257,8 +253,6 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/protobuf v3.11.4+incompatible/go.mod h1:lUQ9D1ePzbH2PrIS7ob/bjm9HXyH5WHB0Akwh7URreM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -347,8 +341,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report/v2 v2.0.0 h1:bMZNO9B16VFn07tKyi4YJFIbZtVmJaa5Xakv9dcwK58= github.com/jstemmer/go-junit-report/v2 v2.0.0/go.mod h1:mgHVr7VUo5Tn8OLVr1cKnLuEy0M92wdRntM99h7RkgQ= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -394,8 +386,6 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= -github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM= github.com/mattn/go-zglob v0.0.4/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= @@ -478,9 +468,6 @@ github.com/redis/go-redis/extra/redisprometheus/v9 v9.0.5 h1:kvl0LOTQD23VR1R7A9v github.com/redis/go-redis/extra/redisprometheus/v9 v9.0.5/go.mod h1:VhyLk7MdSTKbJCx6+wXlj3/ebh49gTq3yBiXymYrG7w= github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/renstrom/shortuuid v3.0.0+incompatible h1:F6T1U7bWlI3FTV+JE8HyeR7bkTeYZJntqQLA9ST4HOQ= github.com/renstrom/shortuuid v3.0.0+incompatible/go.mod h1:n18Ycpn8DijG+h/lLBQVnGKv1BCtTeXo8KKSbBOrQ8c= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -778,8 +765,6 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -917,34 +902,6 @@ k8s.io/kubelet v0.26.15 h1:zf6epB3dqA5bperYLhyuFr+gQQ9qasM95cyeKAuodZc= k8s.io/kubelet v0.26.15/go.mod h1:8g/EzBlR1ByT5jkYbH9iaCNCFKDUNhHj4cx38UrtyiY= k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak= k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= -modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= -modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= -modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= -modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= -modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= -modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= -modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/common/grpc/configuration/types.go b/internal/common/grpc/configuration/types.go index 8b4f1857300..967485f348a 100644 --- a/internal/common/grpc/configuration/types.go +++ b/internal/common/grpc/configuration/types.go @@ -11,11 +11,6 @@ type GrpcConfig struct { Tls TlsConfig } -type GrpcPoolConfig struct { - InitialConnections int - Capacity int -} - type TlsConfig struct { Enabled bool KeyPath string diff --git a/internal/common/grpc/gateway.go b/internal/common/grpc/gateway.go index b45773b5a71..8b6e59dc2ad 100644 --- a/internal/common/grpc/gateway.go +++ b/internal/common/grpc/gateway.go @@ -15,8 +15,6 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" - - protoutil "github.com/armadaproject/armada/internal/common/grpc/protoutils" ) // CreateGatewayHandler configures the gRPC API gateway @@ -35,7 +33,7 @@ func CreateGatewayHandler( grpcAddress := fmt.Sprintf(":%d", grpcPort) - m := new(protoutil.JSONMarshaller) + m := new(runtime.JSONBuiltin) gw := runtime.NewServeMux( runtime.WithMarshalerOption(runtime.MIMEWildcard, m), runtime.WithOutgoingHeaderMatcher(func(key string) (string, bool) { diff --git a/internal/common/grpc/grpcpool/LICENSE b/internal/common/grpc/grpcpool/LICENSE deleted file mode 100644 index a97f34eeb8c..00000000000 --- a/internal/common/grpc/grpcpool/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 ProcessOut - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/internal/common/grpc/grpcpool/README.md b/internal/common/grpc/grpcpool/README.md deleted file mode 100644 index 548c3c35879..00000000000 --- a/internal/common/grpc/grpcpool/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# grpc-go-pool - -[![GoDoc](https://godoc.org/github.com/processout/grpc-go-pool?status.svg)](https://godoc.org/github.com/processout/grpc-go-pool) - -This package aims to provide an easy to use and lightweight GRPC connection pool. - -Please note that the goal isn't to replicate the client-side load-balancing feature of the official grpc package: the goal is rather to have multiple connections established to one endpoint (which can be server-side load-balanced). diff --git a/internal/common/grpc/grpcpool/pool.go b/internal/common/grpc/grpcpool/pool.go deleted file mode 100644 index 27bff57982d..00000000000 --- a/internal/common/grpc/grpcpool/pool.go +++ /dev/null @@ -1,276 +0,0 @@ -// Package grpcpool provides a pool of grpc clients -package grpcpool - -import ( - "container/ring" - "context" - "errors" - "sync" - "time" - - "google.golang.org/grpc" -) - -var ( - // ErrClosed is the error when the client pool is closed - ErrClosed = errors.New("grpc pool: client pool is closed") - // ErrTimeout is the error when the client pool timed out - ErrTimeout = errors.New("grpc pool: client pool timed out") - // ErrAlreadyClosed is the error when the client conn was already closed - ErrAlreadyClosed = errors.New("grpc pool: the connection was already closed") - // ErrFullPool is the error when the pool is already full - ErrFullPool = errors.New("grpc pool: closing a ClientConn into a full pool") -) - -// Factory is a function type creating a grpc client -type Factory func() (*grpc.ClientConn, error) - -// FactoryWithContext is a function type creating a grpc client -// that accepts the context parameter that could be passed from -// Get or NewWithContext method. -type FactoryWithContext func(context.Context) (*grpc.ClientConn, error) - -// Pool is the grpc client pool -type Pool struct { - clients *ring.Ring - factory FactoryWithContext - idleTimeout time.Duration - maxLifeDuration time.Duration - mu sync.RWMutex -} - -// ClientConn is the wrapper for a grpc client conn -type ClientConn struct { - *grpc.ClientConn - ccMutex sync.Mutex - pool *Pool - ring *ring.Ring - timeUsed time.Time - timeInitiated time.Time - unhealthy bool -} - -// New creates a new clients pool with the given initial and maximum capacity, -// and the timeout for the idle clients. Returns an error if the initial -// clients could not be created -func New(factory Factory, init, capacity int, idleTimeout time.Duration, - maxLifeDuration ...time.Duration, -) (*Pool, error) { - return NewWithContext(context.Background(), func(ctx context.Context) (*grpc.ClientConn, error) { return factory() }, - init, capacity, idleTimeout, maxLifeDuration...) -} - -// NewWithContext creates a new clients pool with the given initial and maximum -// capacity, and the timeout for the idle clients. The context parameter would -// be passed to the factory method during initialization. Returns an error if the -// initial clients could not be created. -func NewWithContext(ctx context.Context, factory FactoryWithContext, init, capacity int, idleTimeout time.Duration, - maxLifeDuration ...time.Duration, -) (*Pool, error) { - if capacity <= 0 { - capacity = 1 - } - if init < 0 { - init = 0 - } - if init > capacity { - init = capacity - } - p := &Pool{ - clients: ring.New(capacity), - factory: factory, - idleTimeout: idleTimeout, - } - if len(maxLifeDuration) > 0 { - p.maxLifeDuration = maxLifeDuration[0] - } - for i := 0; i < init; i++ { - c, err := factory(ctx) - if err != nil { - return nil, err - } - - p.clients.Value = &ClientConn{ - ClientConn: c, - pool: p, - ring: p.clients, - timeUsed: time.Now(), - timeInitiated: time.Now(), - } - - p.clients = p.clients.Next() - } - // Fill the rest of the pool with empty clients - for i := 0; i < capacity-init; i++ { - p.clients.Value = &ClientConn{ - pool: p, - ring: p.clients, - } - p.clients = p.clients.Next() - } - return p, nil -} - -func (p *Pool) getClients() *ring.Ring { - return p.clients -} - -// Close empties the pool calling Close on all its clients. -// You can call Close while there are outstanding clients. -// The pool channel is then closed, and Get will not be allowed anymore -func (p *Pool) Close() { - p.mu.Lock() - clients := p.clients - p.clients = nil - p.mu.Unlock() - - if clients == nil { - return - } - - for i := 0; i < clients.Len(); i++ { - if client, ok := clients.Value.(*ClientConn); ok { - if client.ClientConn == nil { - continue - } - client.ClientConn.Close() - } - } -} - -// IsClosed returns true if the client pool is closed. -func (p *Pool) IsClosed() bool { - return p == nil || p.getClients() == nil -} - -// Get will return the next available client. If capacity -// has not been reached, it will create a new one using the factory. -func (p *Pool) Get(ctx context.Context) (*ClientConn, error) { - p.mu.Lock() - defer p.mu.Unlock() - - clients := p.getClients() - if clients == nil { - return nil, ErrClosed - } - - // Every time Get() is called, we advance to the next client in the ring. - // This is essentially round-robin load-balancing. Keeping it simple for now. - p.clients = p.clients.Next() - - client := p.clients.Value.(*ClientConn) - - // Make a new client if there's not one here in the ring already. - if client == nil { - client = &ClientConn{ - pool: p, - ring: p.clients, - } - p.clients.Value = client - } - - // If the wrapper was idle too long, close the connection and create a new - // one. It's safe to assume that there isn't any newer client as the client - // we fetched is the first in the channel - idleTimeout := p.idleTimeout - if client.ClientConn != nil && idleTimeout > 0 && - client.timeUsed.Add(idleTimeout).Before(time.Now()) { - - client.ClientConn.Close() - client.dispose() - } - - var err error - var conn *grpc.ClientConn - if client.ClientConn == nil || - client.unhealthy { - conn, err = p.factory(ctx) - if err != nil { - return nil, err - } - client.revive(conn) - client.unhealthy = false - // This is a new connection, reset its initiated time - client.timeInitiated = time.Now() - } - - client.timeUsed = time.Now() - - // This way a user of ClientConn can call ClientConn.Close() and not - // get to keep using the client. - wrapper := &ClientConn{ - ClientConn: client.ClientConn, - pool: client.pool, - ring: client.ring, - timeUsed: client.timeUsed, - timeInitiated: client.timeInitiated, - unhealthy: client.unhealthy, - } - - return wrapper, err -} - -// Unhealthy marks the client conn as unhealthy, so that the connection -// gets reset when closed. -func (c *ClientConn) Unhealthy() { - c.unhealthy = true - // If this copy's grpc connection is unhealthy, so is the one held by - // the pool's ring. - // FIXME: Should we use a shared context instead? - c.pool.mu.Lock() - defer c.pool.mu.Unlock() - client := c.ring.Value.(*ClientConn) - if client != nil { - client.unhealthy = true - } -} - -func (c *ClientConn) revive(conn *grpc.ClientConn) { - c.ccMutex.Lock() - defer c.ccMutex.Unlock() - c.ClientConn = conn -} - -func (c *ClientConn) dispose() { - c.ccMutex.Lock() - defer c.ccMutex.Unlock() - c.ClientConn = nil -} - -// Close 'returns' a ClientConn to the pool. It is safe to call multiple time, -// but will return an error after first time. Note that grpc connections can -// be safeuly utilized concurrently by many clients. Therefore there's no -// real need to grant exclusive use of a connection to one client at a time. -func (c *ClientConn) Close() error { - if c == nil { - return nil - } - if c.ClientConn == nil { - return ErrAlreadyClosed - } - if c.pool.IsClosed() { - return ErrClosed - } - // If the wrapper connection has become too old, we want to recycle it. To - // clarify the logic: if the sum of the initialization time and the max - // duration is before Now(), it means the initialization is so old adding - // the maximum duration couldn't put in the future. This sum therefore - // corresponds to the cut-off point: if it's in the future we still have - // time, if it's in the past it's too old - maxDuration := c.pool.maxLifeDuration - if maxDuration > 0 && c.timeInitiated.Add(maxDuration).Before(time.Now()) { - c.Unhealthy() - } - - c.dispose() - - return nil -} - -// Capacity returns the capacity -func (p *Pool) Capacity() int { - if p.IsClosed() { - return 0 - } - return p.clients.Len() -} diff --git a/internal/common/grpc/grpcpool/pool_test.go b/internal/common/grpc/grpcpool/pool_test.go deleted file mode 100644 index 5868df96952..00000000000 --- a/internal/common/grpc/grpcpool/pool_test.go +++ /dev/null @@ -1,233 +0,0 @@ -package grpcpool - -import ( - "context" - "testing" - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/connectivity" -) - -func TestNew(t *testing.T) { - p, err := New(func() (*grpc.ClientConn, error) { - return grpc.Dial("example.com", grpc.WithInsecure()) - }, 1, 3, 0) - if err != nil { - t.Errorf("The pool returned an error: %s", err.Error()) - } - if a := p.Capacity(); a != 3 { - t.Errorf("The pool capacity was %d but should be 3", a) - } - - // Get a client - client, err := p.Get(context.Background()) - if err != nil { - t.Errorf("Get returned an error: %s", err.Error()) - } - if client == nil { - t.Error("client was nil") - } - if a := p.Capacity(); a != 3 { - t.Errorf("The pool capacity was %d but should be 3", a) - } - - // Return the client - err = client.Close() - if err != nil { - t.Errorf("Close returned an error: %s", err.Error()) - } - if a := p.Capacity(); a != 3 { - t.Errorf("The pool capacity was %d but should be 3", a) - } - - // Attempt to return the client again - err = client.Close() - if err != ErrAlreadyClosed { - t.Errorf("Expected error \"%s\" but got \"%s\"", - ErrAlreadyClosed.Error(), err.Error()) - } - - // Take 3 clients - cl1, err1 := p.Get(context.Background()) - cl2, err2 := p.Get(context.Background()) - cl3, err3 := p.Get(context.Background()) - if err1 != nil { - t.Errorf("Err1 was not nil: %s", err1.Error()) - } - if err2 != nil { - t.Errorf("Err2 was not nil: %s", err2.Error()) - } - if err3 != nil { - t.Errorf("Err3 was not nil: %s", err3.Error()) - } - - if a := p.Capacity(); a != 3 { - t.Errorf("The pool capacity was %d but should be 3", a) - } - - // Returning all of them - err1 = cl1.Close() - if err1 != nil { - t.Errorf("Close returned an error: %s", err1.Error()) - } - err2 = cl2.Close() - if err2 != nil { - t.Errorf("Close returned an error: %s", err2.Error()) - } - err3 = cl3.Close() - if err3 != nil { - t.Errorf("Close returned an error: %s", err3.Error()) - } -} - -func TestMaxLifeDuration(t *testing.T) { - p, err := New(func() (*grpc.ClientConn, error) { - return grpc.Dial("example.com", grpc.WithInsecure()) - }, 1, 1, 0, 1) - if err != nil { - t.Errorf("The pool returned an error: %s", err.Error()) - } - - c, err := p.Get(context.Background()) - if err != nil { - t.Errorf("Get returned an error: %s", err.Error()) - } - - // The max life of the connection was very low (1ns), so when we close - // the connection it should get marked as unhealthy - if err := c.Close(); err != nil { - t.Errorf("Close returned an error: %s", err.Error()) - } - if !c.unhealthy { - t.Errorf("the connection should've been marked as unhealthy") - } - - // Let's also make sure we don't prematurely close the connection - count := 0 - p, err = New(func() (*grpc.ClientConn, error) { - count++ - return grpc.Dial("example.com", grpc.WithInsecure()) - }, 1, 1, 0, time.Minute) - if err != nil { - t.Errorf("The pool returned an error: %s", err.Error()) - } - - for i := 0; i < 3; i++ { - c, err = p.Get(context.Background()) - if err != nil { - t.Errorf("Get returned an error: %s", err.Error()) - } - - // The max life of the connection is high, so when we close - // the connection it shouldn't be marked as unhealthy - if err := c.Close(); err != nil { - t.Errorf("Close returned an error: %s", err.Error()) - } - if c.unhealthy { - t.Errorf("the connection shouldn't have been marked as unhealthy") - } - } - - // Count should have been 1 as dial function should only have been called once - if count > 1 { - t.Errorf("Dial function has been called multiple times") - } -} - -func TestPoolClose(t *testing.T) { - p, err := New(func() (*grpc.ClientConn, error) { - return grpc.Dial("example.com", grpc.WithInsecure()) - }, 1, 1, 0) - if err != nil { - t.Errorf("The pool returned an error: %s", err.Error()) - } - - c, err := p.Get(context.Background()) - if err != nil { - t.Errorf("Get returned an error: %s", err.Error()) - } - - cc := c.ClientConn - if err := c.Close(); err != nil { - t.Errorf("Close returned an error: %s", err.Error()) - } - - // Close pool should close all underlying gRPC client connections - p.Close() - - if cc.GetState() != connectivity.Shutdown { - t.Errorf("Returned connection was not closed, underlying connection is not in shutdown state") - } -} - -func TestContextCancelation(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - _, err := NewWithContext(ctx, func(ctx context.Context) (*grpc.ClientConn, error) { - select { - case <-ctx.Done(): - return nil, ctx.Err() - - default: - return grpc.Dial("example.com", grpc.WithInsecure()) - } - }, 1, 1, 0) - - if err != context.Canceled { - t.Errorf("Returned error was not context.Canceled, but the context did cancel before the invocation") - } -} - -func TestContextTimeout(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Microsecond) - defer cancel() - - _, err := NewWithContext(ctx, func(ctx context.Context) (*grpc.ClientConn, error) { - select { - case <-ctx.Done(): - return nil, ctx.Err() - - // wait for the deadline to pass - case <-time.After(time.Millisecond): - return grpc.Dial("example.com", grpc.WithInsecure()) - } - }, 1, 1, 0) - - if err != context.DeadlineExceeded { - t.Errorf("Returned error was not context.DeadlineExceeded, but the context was timed out before the initialization") - } -} - -func TestGetContextFactoryTimeout(t *testing.T) { - p, err := NewWithContext(context.Background(), func(ctx context.Context) (*grpc.ClientConn, error) { - select { - case <-ctx.Done(): - return nil, ctx.Err() - - // wait for the deadline to pass - case <-time.After(time.Millisecond): - return grpc.Dial("example.com", grpc.WithInsecure()) - } - }, 1, 1, 0) - if err != nil { - t.Errorf("The pool returned an error: %s", err.Error()) - } - - // mark as unhealthy the available conn - c, err := p.Get(context.Background()) - if err != nil { - t.Errorf("Get returned an error: %s", err.Error()) - } - c.Unhealthy() - c.Close() - - ctx, cancel := context.WithTimeout(context.Background(), time.Microsecond) - defer cancel() - - _, err = p.Get(ctx) - if err != context.DeadlineExceeded { - t.Errorf("Returned error was not context.DeadlineExceeded, but the context was timed out before the Get invocation") - } -} diff --git a/internal/common/grpc/protoutils/json_marshaller.go b/internal/common/grpc/protoutils/json_marshaller.go deleted file mode 100644 index 7fff15d433e..00000000000 --- a/internal/common/grpc/protoutils/json_marshaller.go +++ /dev/null @@ -1,39 +0,0 @@ -package protoutil - -import ( - "encoding/json" - "io" - - "github.com/coreos/pkg/httputil" - gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime" -) - -// Minimal implementation of marshaller using default json package, this assumes all proto messages can be nicely marshalled with it -// For kubernetes objects this works much better then default JSONpb -// To handle one of feature of protocol bufers custom json marshaller is required - -type JSONMarshaller struct{} - -func (*JSONMarshaller) ContentType() string { - return httputil.JSONContentType -} - -func (j *JSONMarshaller) Marshal(v interface{}) ([]byte, error) { - return json.Marshal(v) -} - -func (j *JSONMarshaller) Unmarshal(data []byte, v interface{}) error { - return json.Unmarshal(data, v) -} - -func (j *JSONMarshaller) NewDecoder(r io.Reader) gwruntime.Decoder { - return json.NewDecoder(r) -} - -func (j *JSONMarshaller) NewEncoder(w io.Writer) gwruntime.Encoder { - return json.NewEncoder(w) -} - -func (*JSONMarshaller) Delimiter() []byte { - return []byte("\n") -} diff --git a/internal/jobservice/application.go b/internal/jobservice/application.go deleted file mode 100644 index 2ae6be4a593..00000000000 --- a/internal/jobservice/application.go +++ /dev/null @@ -1,187 +0,0 @@ -package jobservice - -import ( - "context" - "fmt" - "net" - "os" - "time" - - log "github.com/sirupsen/logrus" - "golang.org/x/sync/errgroup" - "google.golang.org/grpc" - - "github.com/armadaproject/armada/internal/common/auth" - grpcCommon "github.com/armadaproject/armada/internal/common/grpc" - grpcconfig "github.com/armadaproject/armada/internal/common/grpc/configuration" - "github.com/armadaproject/armada/internal/common/grpc/grpcpool" - "github.com/armadaproject/armada/internal/jobservice/configuration" - "github.com/armadaproject/armada/internal/jobservice/events" - "github.com/armadaproject/armada/internal/jobservice/eventstojobs" - "github.com/armadaproject/armada/internal/jobservice/repository" - "github.com/armadaproject/armada/internal/jobservice/server" - js "github.com/armadaproject/armada/pkg/api/jobservice" - "github.com/armadaproject/armada/pkg/client" -) - -type App struct { - // Configuration for jobService - Config *configuration.JobServiceConfiguration -} - -func New() *App { - return &App{} -} - -var DefaultConfiguration = &configuration.JobServiceConfiguration{ - GrpcPool: grpcconfig.GrpcPoolConfig{ - InitialConnections: 5, - Capacity: 5, - }, - SubscriberPoolSize: 30, - SubscriptionExpirySecs: 300, - PurgeJobSetTime: 600, -} - -// Mutates config where possible to correct mis-configurations. -func RectifyConfig(config *configuration.JobServiceConfiguration) { - logger := log.WithField("JobService", "RectifyConfig") - - if config.SubscriptionExpirySecs == 0 { - logger.WithFields(log.Fields{ - "default": DefaultConfiguration.SubscriptionExpirySecs, - "configured": config.SubscriptionExpirySecs, - }).Warn("config.SubscriptionExpirySecs invalid, using default instead") - config.SubscriptionExpirySecs = DefaultConfiguration.SubscriptionExpirySecs - } - - if config.PurgeJobSetTime == 0 { - logger.WithFields(log.Fields{ - "default": DefaultConfiguration.PurgeJobSetTime, - "configured": config.PurgeJobSetTime, - }).Warn("config.PurgeJobSetTime invalid, using default instead") - config.PurgeJobSetTime = DefaultConfiguration.PurgeJobSetTime - } - - // Grpc Pool - if config.GrpcPool.InitialConnections <= 0 { - logger.WithFields(log.Fields{ - "default": DefaultConfiguration.GrpcPool.InitialConnections, - "configured": config.GrpcPool.InitialConnections, - }).Warn("config.GrpcPool.InitialConnections invalid, using default instead") - config.GrpcPool.InitialConnections = DefaultConfiguration.GrpcPool.InitialConnections - } - if config.GrpcPool.Capacity <= 0 { - logger.WithFields(log.Fields{ - "default": DefaultConfiguration.GrpcPool.Capacity, - "configured": config.GrpcPool.Capacity, - }).Warn("config.GrpcPool.Capacity invalid, using default instead") - config.GrpcPool.Capacity = DefaultConfiguration.GrpcPool.Capacity - } - - if config.SubscriberPoolSize <= 0 { - logger.WithFields(log.Fields{ - "default": DefaultConfiguration.SubscriberPoolSize, - "configured": config.SubscriberPoolSize, - }).Warn("config.SubscriberPoolSize invalid, using default instead") - config.SubscriberPoolSize = DefaultConfiguration.SubscriberPoolSize - } - - if config.ApiConnection.ForceNoTls { - logger.Warn("Armada Server connection will be unsecured! TLS is forced OFF!") - } - - return -} - -func (a *App) StartUp(ctx context.Context, config *configuration.JobServiceConfiguration) error { - // Setup an errgroup that cancels on any job failing or there being no active jobs. - g, _ := errgroup.WithContext(ctx) - - RectifyConfig(config) - - if os.Getenv("JOBSERVICE_DEBUG") != "" { - log.SetLevel(log.DebugLevel) - log.Debug("Set logging to debug level") - log.Debugf("Subscription expiry time: %d", config.SubscriptionExpirySecs) - } - - log := log.WithField("JobService", "Startup") - grpcServer := grpcCommon.CreateGrpcServer( - config.Grpc.KeepaliveParams, - config.Grpc.KeepaliveEnforcementPolicy, - []auth.AuthService{&auth.AnonymousAuthService{}}, - config.Grpc.Tls, - ) - - err, sqlJobRepo, dbCallbackFn := repository.NewSQLJobService(config, log) - if err != nil { - panic(err) - } - defer dbCallbackFn() - sqlJobRepo.Setup(ctx) - jobService := server.NewJobService(config, sqlJobRepo) - js.RegisterJobServiceServer(grpcServer, jobService) - - lc := net.ListenConfig{} - lis, err := lc.Listen(ctx, "tcp", fmt.Sprintf(":%d", config.GrpcPort)) - if err != nil { - return err - } - - connFactory := func(ctx context.Context) (*grpc.ClientConn, error) { - return client.CreateApiConnection(&config.ApiConnection) - } - - // Start a pool - evConnPool, err := grpcpool.NewWithContext(ctx, connFactory, - config.GrpcPool.InitialConnections, - config.GrpcPool.Capacity, - 0) - if err != nil { - return err - } - - g.Go(func() error { - eventClient := events.NewPooledEventClient(evConnPool) - // Runs continuously until ctx is canceled or it runs into an unrecoverable error - jobSubExecutor := eventstojobs.NewJobSetSubscriptionExecutor( - ctx, - eventClient, - sqlJobRepo, - jobService.GetNewSubscriptionChannel(), - time.Duration(config.SubscriptionExpirySecs)*time.Second) - jobSubExecutor.Manage() - return nil - }) - - g.Go(func() error { - defer log.Infof("stopping server.") - - go func() { - select { - case <-ctx.Done(): - log.Info("Got context done for grpc server.") - grpcServer.Stop() - } - }() - - log.Info("jobservice service listening on ", config.GrpcPort) - if err := grpcServer.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) - } - - return nil - }) - g.Go(func() error { - sqlJobRepo.PurgeExpiredJobSets(ctx) - return nil - }) - - if err := g.Wait(); err != nil { - log.Fatalf("error detected on wait %v", err) - return err - } - - return nil -} diff --git a/internal/jobservice/application_test.go b/internal/jobservice/application_test.go deleted file mode 100644 index a5820f5947e..00000000000 --- a/internal/jobservice/application_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package jobservice - -import ( - "testing" - - "github.com/stretchr/testify/require" - - grpcconfig "github.com/armadaproject/armada/internal/common/grpc/configuration" - "github.com/armadaproject/armada/internal/jobservice/configuration" -) - -var knownGoodConfig = DefaultConfiguration - -func TestRectifyConfig(t *testing.T) { - testCases := []struct { - name string - config *configuration.JobServiceConfiguration - expectedConfig *configuration.JobServiceConfiguration - }{ - { - name: "S'all good", - config: knownGoodConfig, - expectedConfig: knownGoodConfig, - }, - { - name: "Zero-length SubscriberPoolSize", - config: &configuration.JobServiceConfiguration{ - SubscriberPoolSize: 0, - }, - expectedConfig: knownGoodConfig, - }, - { - name: "Incorrect GrpcPool.InitialConnections", - config: &configuration.JobServiceConfiguration{ - GrpcPool: grpcconfig.GrpcPoolConfig{InitialConnections: 0, Capacity: knownGoodConfig.GrpcPool.Capacity}, - }, - expectedConfig: knownGoodConfig, - }, - { - name: "Incorrect GrpcPool.Capacity", - config: &configuration.JobServiceConfiguration{ - GrpcPool: grpcconfig.GrpcPoolConfig{InitialConnections: knownGoodConfig.GrpcPool.InitialConnections, Capacity: 0}, - }, - expectedConfig: knownGoodConfig, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - RectifyConfig(tc.config) - require.Equal(t, tc.expectedConfig, tc.config) - }) - } -} diff --git a/internal/jobservice/configuration/types.go b/internal/jobservice/configuration/types.go deleted file mode 100644 index 11ecf67b98d..00000000000 --- a/internal/jobservice/configuration/types.go +++ /dev/null @@ -1,42 +0,0 @@ -package configuration - -import ( - "time" - - grpcconfig "github.com/armadaproject/armada/internal/common/grpc/configuration" - "github.com/armadaproject/armada/pkg/client" -) - -type PostgresConfig struct { - PoolMaxOpenConns int - PoolMaxIdleConns int - PoolMaxConnLifetime time.Duration - Connection map[string]string -} - -type JobServiceConfiguration struct { - HttpPort uint16 - GrpcPort uint16 - MetricsPort uint16 - - Grpc grpcconfig.GrpcConfig - GrpcPool grpcconfig.GrpcPoolConfig - // Connection details that we obtain from client - ApiConnection client.ApiConnectionDetails - // Configurable value that translates to number of seconds - // until a job set subscription is considered expired. - SubscriptionExpirySecs int64 - // Size of the goroutine pool for processing job-set subscriptions - SubscriberPoolSize int - // Purge jobSets if not updated in this number of seconds - PurgeJobSetTime int64 - // Type of database used - must be either 'postgres' or 'sqlite' - DatabaseType string - // Absolute or relative path for sqlite database and must include the db name - // This field is only read when DatabaseType is 'sqlite' - DatabasePath string - - // Configuration details for using a Postgres database; this field is - // ignored if the DatabaseType above is not 'postgres' - PostgresConfig PostgresConfig -} diff --git a/internal/jobservice/events/client.go b/internal/jobservice/events/client.go deleted file mode 100644 index c76c99b5f71..00000000000 --- a/internal/jobservice/events/client.go +++ /dev/null @@ -1,141 +0,0 @@ -//go:generate moq -out client_moq.go . JobEventReader -package events - -import ( - "context" - "sync" - - "google.golang.org/grpc" - - "github.com/gogo/protobuf/types" - - "github.com/armadaproject/armada/internal/common/grpc/grpcpool" - "github.com/armadaproject/armada/pkg/api" - "github.com/armadaproject/armada/pkg/client" -) - -// JobEventReader is the interface for retrieving job set event messages -type JobEventReader interface { - GetJobEventMessage(ctx context.Context, jobReq *api.JobSetRequest) (api.Event_GetJobSetEventsClient, error) - Health(ctx context.Context, empty *types.Empty) (*api.HealthCheckResponse, error) - Close() -} - -// EventClient is the local struct for retrieving events from the api using the grpc client -type EventClient struct { - config *client.ApiConnectionDetails - conn *grpc.ClientConn - mux *sync.Mutex -} - -// NewEventClient returns a new EventClient -func NewEventClient(config *client.ApiConnectionDetails) *EventClient { - return &EventClient{ - config: config, - mux: &sync.Mutex{}, - } -} - -// GetJobEventMessage performs all the steps for obtaining an event message -func (ec *EventClient) GetJobEventMessage(ctx context.Context, jobReq *api.JobSetRequest) (api.Event_GetJobSetEventsClient, error) { - err := ec.ensureApiConnection() - if err != nil { - return nil, err - } - eventClient := api.NewEventClient(ec.conn) - - stream, err := eventClient.GetJobSetEvents(ctx, jobReq) - if err != nil { - return nil, err - } - return stream, nil -} - -func (ec *EventClient) Health(ctx context.Context, empty *types.Empty) (*api.HealthCheckResponse, error) { - err := ec.ensureApiConnection() - if err != nil { - return nil, err - } - eventClient := api.NewEventClient(ec.conn) - - health, err := eventClient.Health(ctx, empty) - return health, err -} - -// Close will close the api connection if established -func (ec *EventClient) Close() { - ec.mux.Lock() - defer ec.mux.Unlock() - - if ec.hasConn() { - ec.conn.Close() - ec.conn = nil - } -} - -// hasConn tests whether client already has an api conn -func (ec *EventClient) hasConn() bool { - return ec.conn != nil -} - -// ensureApiConnection will establish api connection if needed -func (ec *EventClient) ensureApiConnection() error { - if ec.hasConn() { - return nil - } - - ec.mux.Lock() - defer ec.mux.Unlock() - - conn, connErr := client.CreateApiConnection(ec.config) - if connErr != nil { - return connErr - } - ec.conn = conn - - return nil -} - -type PooledEventClient struct { - pool *grpcpool.Pool -} - -func NewPooledEventClient(pool *grpcpool.Pool) *PooledEventClient { - return &PooledEventClient{ - pool: pool, - } -} - -// GetJobEventMessage performs all the steps for obtaining an event message -func (pec *PooledEventClient) GetJobEventMessage(ctx context.Context, jobReq *api.JobSetRequest) (api.Event_GetJobSetEventsClient, error) { - cc, err := pec.pool.Get(ctx) - if err != nil { - return nil, err - } - defer cc.Close() - eventClient := api.NewEventClient(cc.ClientConn) - - stream, err := eventClient.GetJobSetEvents(ctx, jobReq) - if err != nil { - return nil, err - } - return stream, nil -} - -func (pec *PooledEventClient) Health(ctx context.Context, empty *types.Empty) (*api.HealthCheckResponse, error) { - cc, err := pec.pool.Get(ctx) - if err != nil { - return nil, err - } - defer cc.Close() - eventClient := api.NewEventClient(cc.ClientConn) - - health, err := eventClient.Health(ctx, empty) - if err != nil { - cc.Unhealthy() - return nil, err - } - return health, err -} - -func (ec *PooledEventClient) Close() {} diff --git a/internal/jobservice/events/client_moq.go b/internal/jobservice/events/client_moq.go deleted file mode 100644 index efb2cf595d8..00000000000 --- a/internal/jobservice/events/client_moq.go +++ /dev/null @@ -1,172 +0,0 @@ -// Code generated by moq; DO NOT EDIT. -// github.com/matryer/moq - -package events - -import ( - "context" - "sync" - - "github.com/gogo/protobuf/types" - - "github.com/armadaproject/armada/pkg/api" -) - -// Ensure, that JobEventReaderMock does implement JobEventReader. -// If this is not the case, regenerate this file with moq. -var _ JobEventReader = &JobEventReaderMock{} - -// JobEventReaderMock is a mock implementation of JobEventReader. -// -// func TestSomethingThatUsesJobEventReader(t *testing.T) { -// -// // make and configure a mocked JobEventReader -// mockedJobEventReader := &JobEventReaderMock{ -// CloseFunc: func() { -// panic("mock out the Close method") -// }, -// GetJobEventMessageFunc: func(ctx context.Context, jobReq *api.JobSetRequest) (api.Event_GetJobSetEventsClient, error) { -// panic("mock out the GetJobEventMessage method") -// }, -// HealthFunc: func(ctx context.Context, empty *types.Empty) (*api.HealthCheckResponse, error) { -// panic("mock out the Health method") -// }, -// } -// -// // use mockedJobEventReader in code that requires JobEventReader -// // and then make assertions. -// -// } -type JobEventReaderMock struct { - // CloseFunc mocks the Close method. - CloseFunc func() - - // GetJobEventMessageFunc mocks the GetJobEventMessage method. - GetJobEventMessageFunc func(ctx context.Context, jobReq *api.JobSetRequest) (api.Event_GetJobSetEventsClient, error) - - // HealthFunc mocks the Health method. - HealthFunc func(ctx context.Context, empty *types.Empty) (*api.HealthCheckResponse, error) - - // calls tracks calls to the methods. - calls struct { - // Close holds details about calls to the Close method. - Close []struct { - } - // GetJobEventMessage holds details about calls to the GetJobEventMessage method. - GetJobEventMessage []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // JobReq is the jobReq argument value. - JobReq *api.JobSetRequest - } - // Health holds details about calls to the Health method. - Health []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Empty is the empty argument value. - Empty *types.Empty - } - } - lockClose sync.RWMutex - lockGetJobEventMessage sync.RWMutex - lockHealth sync.RWMutex -} - -// Close calls CloseFunc. -func (mock *JobEventReaderMock) Close() { - if mock.CloseFunc == nil { - panic("JobEventReaderMock.CloseFunc: method is nil but JobEventReader.Close was just called") - } - callInfo := struct { - }{} - mock.lockClose.Lock() - mock.calls.Close = append(mock.calls.Close, callInfo) - mock.lockClose.Unlock() - mock.CloseFunc() -} - -// CloseCalls gets all the calls that were made to Close. -// Check the length with: -// -// len(mockedJobEventReader.CloseCalls()) -func (mock *JobEventReaderMock) CloseCalls() []struct { -} { - var calls []struct { - } - mock.lockClose.RLock() - calls = mock.calls.Close - mock.lockClose.RUnlock() - return calls -} - -// GetJobEventMessage calls GetJobEventMessageFunc. -func (mock *JobEventReaderMock) GetJobEventMessage(ctx context.Context, jobReq *api.JobSetRequest) (api.Event_GetJobSetEventsClient, error) { - if mock.GetJobEventMessageFunc == nil { - panic("JobEventReaderMock.GetJobEventMessageFunc: method is nil but JobEventReader.GetJobEventMessage was just called") - } - callInfo := struct { - Ctx context.Context - JobReq *api.JobSetRequest - }{ - Ctx: ctx, - JobReq: jobReq, - } - mock.lockGetJobEventMessage.Lock() - mock.calls.GetJobEventMessage = append(mock.calls.GetJobEventMessage, callInfo) - mock.lockGetJobEventMessage.Unlock() - return mock.GetJobEventMessageFunc(ctx, jobReq) -} - -// GetJobEventMessageCalls gets all the calls that were made to GetJobEventMessage. -// Check the length with: -// -// len(mockedJobEventReader.GetJobEventMessageCalls()) -func (mock *JobEventReaderMock) GetJobEventMessageCalls() []struct { - Ctx context.Context - JobReq *api.JobSetRequest -} { - var calls []struct { - Ctx context.Context - JobReq *api.JobSetRequest - } - mock.lockGetJobEventMessage.RLock() - calls = mock.calls.GetJobEventMessage - mock.lockGetJobEventMessage.RUnlock() - return calls -} - -// Health calls HealthFunc. -func (mock *JobEventReaderMock) Health(ctx context.Context, empty *types.Empty) (*api.HealthCheckResponse, error) { - if mock.HealthFunc == nil { - panic("JobEventReaderMock.HealthFunc: method is nil but JobEventReader.Health was just called") - } - callInfo := struct { - Ctx context.Context - Empty *types.Empty - }{ - Ctx: ctx, - Empty: empty, - } - mock.lockHealth.Lock() - mock.calls.Health = append(mock.calls.Health, callInfo) - mock.lockHealth.Unlock() - return mock.HealthFunc(ctx, empty) -} - -// HealthCalls gets all the calls that were made to Health. -// Check the length with: -// -// len(mockedJobEventReader.HealthCalls()) -func (mock *JobEventReaderMock) HealthCalls() []struct { - Ctx context.Context - Empty *types.Empty -} { - var calls []struct { - Ctx context.Context - Empty *types.Empty - } - mock.lockHealth.RLock() - calls = mock.calls.Health - mock.lockHealth.RUnlock() - return calls -} diff --git a/internal/jobservice/events/client_test.go b/internal/jobservice/events/client_test.go deleted file mode 100644 index 11f686693a7..00000000000 --- a/internal/jobservice/events/client_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package events - -import ( - "context" - "net" - "testing" - - "github.com/gogo/protobuf/types" - "github.com/stretchr/testify/require" - "google.golang.org/grpc" - - "github.com/armadaproject/armada/internal/common/grpc/grpcpool" - "github.com/armadaproject/armada/pkg/api" - "github.com/armadaproject/armada/pkg/client" -) - -type DummyEventServer struct{} - -func (des *DummyEventServer) GetJobSetEvents(request *api.JobSetRequest, stream api.Event_GetJobSetEventsServer) error { - return stream.Send(&api.EventStreamMessage{ - Id: "1", - Message: &api.EventMessage{}, - }) -} - -func (des *DummyEventServer) Health(ctx context.Context, cont_ *types.Empty) (*api.HealthCheckResponse, error) { - return new(api.HealthCheckResponse), nil -} - -func (des *DummyEventServer) Watch(req *api.WatchRequest, stream api.Event_WatchServer) error { - return nil -} - -func startTestGrpcServer(t *testing.T) *grpc.Server { - grpcServer := grpc.NewServer() - dummyEventServer := DummyEventServer{} - api.RegisterEventServer(grpcServer, &dummyEventServer) - lis, err := net.Listen("tcp", ":31337") - require.NoError(t, err) - go func() { - defer grpcServer.Stop() - err = grpcServer.Serve(lis) - require.NoError(t, err) - }() - return grpcServer -} - -func connFactory() (*grpc.ClientConn, error) { - return client.CreateApiConnection(&client.ApiConnectionDetails{ - ArmadaUrl: "localhost:31337", - ForceNoTls: true, - }) -} - -func getTestPool() (*grpcpool.Pool, error) { - return grpcpool.New(connFactory, 5, 5, 0) -} - -func TestPooledEventClient(t *testing.T) { - _ = startTestGrpcServer(t) - - pool, err := getTestPool() - require.NoError(t, err) - - client := NewPooledEventClient(pool) - - // This ensures the pooled client will cycle through every connection in the pool. - for i := 0; i < 10; i++ { - response, err := client.Health(context.Background(), &types.Empty{}) - require.NoError(t, err) - require.Equal(t, &api.HealthCheckResponse{}, response) - - eventMessage, err := client.GetJobEventMessage(context.Background(), &api.JobSetRequest{}) - require.NoError(t, err) - for { - _, err := eventMessage.Recv() - // eventually there is an error receiving which is expected - if err != nil { - break - } - } - } -} diff --git a/internal/jobservice/eventstojobs/event_job_response.go b/internal/jobservice/eventstojobs/event_job_response.go deleted file mode 100644 index 543b3900bfe..00000000000 --- a/internal/jobservice/eventstojobs/event_job_response.go +++ /dev/null @@ -1,45 +0,0 @@ -package eventstojobs - -import ( - "github.com/armadaproject/armada/pkg/api" - js "github.com/armadaproject/armada/pkg/api/jobservice" -) - -// Translates api.EventMessage to a JobServiceReponse. -// Nil if api.EventMessage is not a relevant event for JobServiceResponse -func EventsToJobResponse(message api.EventMessage) *js.JobServiceResponse { - switch message.Events.(type) { - case *api.EventMessage_Submitted: - return &js.JobServiceResponse{State: js.JobServiceResponse_SUBMITTED} - case *api.EventMessage_Running: - return &js.JobServiceResponse{State: js.JobServiceResponse_RUNNING} - case *api.EventMessage_Failed: - return &js.JobServiceResponse{State: js.JobServiceResponse_FAILED, Error: message.GetFailed().Reason} - case *api.EventMessage_Succeeded: - return &js.JobServiceResponse{State: js.JobServiceResponse_SUCCEEDED} - case *api.EventMessage_Cancelled: - return &js.JobServiceResponse{State: js.JobServiceResponse_CANCELLED} - } - - return nil -} - -// Check if api.EventMessage is terminal event -func IsEventTerminal(message api.EventMessage) bool { - switch message.Events.(type) { - case *api.EventMessage_Cancelled, *api.EventMessage_Succeeded, *api.EventMessage_Failed: - return true - default: - return false - } -} - -// Check if JobServiceResponse is terminal -func IsStateTerminal(State js.JobServiceResponse_State) bool { - switch State { - case js.JobServiceResponse_DUPLICATE_FOUND, js.JobServiceResponse_CANCELLED, js.JobServiceResponse_SUCCEEDED, js.JobServiceResponse_FAILED: - return true - default: - return false - } -} diff --git a/internal/jobservice/eventstojobs/event_job_response_test.go b/internal/jobservice/eventstojobs/event_job_response_test.go deleted file mode 100644 index 7b857058d9a..00000000000 --- a/internal/jobservice/eventstojobs/event_job_response_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package eventstojobs - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/armadaproject/armada/pkg/api" - "github.com/armadaproject/armada/pkg/api/jobservice" -) - -type response struct { - eventMessage api.EventMessage - jobResponse *jobservice.JobServiceResponse -} - -type eventResponse struct { - eventMessage api.EventMessage - jobServiceEvent bool -} - -func TestIsEventResponse(t *testing.T) { - eventMessages := []response{ - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Submitted{}}, - jobResponse: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUBMITTED}, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Running{}}, - jobResponse: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_RUNNING}, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Failed{Failed: &api.JobFailedEvent{Reason: "Failed Test"}}}, - jobResponse: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_FAILED, Error: "Failed Test"}, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Succeeded{}}, - jobResponse: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUCCEEDED}, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Cancelled{}}, - jobResponse: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_CANCELLED}, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Queued{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Pending{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Cancelling{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_IngressInfo{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_LeaseExpired{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_LeaseReturned{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Leased{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Terminated{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_UnableToSchedule{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Reprioritized{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Reprioritized{}}, - jobResponse: nil, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Utilisation{}}, - jobResponse: nil, - }, - } - length := len(eventMessages) - assert.Equal(t, length, 17) - for i := range eventMessages { - jobResponse := EventsToJobResponse(eventMessages[i].eventMessage) - assert.Equal(t, jobResponse, eventMessages[i].jobResponse) - } -} - -func TestIsTerminalEvent(t *testing.T) { - eventMessages := []eventResponse{ - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Submitted{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Running{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Failed{Failed: &api.JobFailedEvent{Reason: "Failed Test"}}}, - jobServiceEvent: true, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Succeeded{}}, - jobServiceEvent: true, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Cancelled{}}, - jobServiceEvent: true, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Queued{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Pending{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Cancelling{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_IngressInfo{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_LeaseExpired{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_LeaseReturned{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Leased{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Terminated{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_UnableToSchedule{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Reprioritized{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Reprioritized{}}, - jobServiceEvent: false, - }, - { - eventMessage: api.EventMessage{Events: &api.EventMessage_Utilisation{}}, - jobServiceEvent: false, - }, - } - length := len(eventMessages) - assert.Equal(t, length, 17) - for i := range eventMessages { - jobResponse := IsEventTerminal(eventMessages[i].eventMessage) - assert.Equal(t, jobResponse, eventMessages[i].jobServiceEvent) - } -} - -type isStateResponse struct { - state *jobservice.JobServiceResponse - terminalState bool -} - -func TestIsTerminalState(t *testing.T) { - stateMessages := []isStateResponse{ - { - state: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_CANCELLED}, - terminalState: true, - }, - { - state: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUCCEEDED}, - terminalState: true, - }, - { - state: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_FAILED}, - terminalState: true, - }, - { - state: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUBMITTED}, - terminalState: false, - }, - { - state: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_RUNNING}, - terminalState: false, - }, - { - state: &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_DUPLICATE_FOUND}, - terminalState: true, - }, - } - length := len(stateMessages) - assert.Equal(t, length, 6) - for i := range stateMessages { - stateTerminal := IsStateTerminal(stateMessages[i].state.State) - assert.Equal(t, stateTerminal, stateMessages[i].terminalState) - } -} diff --git a/internal/jobservice/eventstojobs/manage_subs.go b/internal/jobservice/eventstojobs/manage_subs.go deleted file mode 100644 index 81717e1cf1e..00000000000 --- a/internal/jobservice/eventstojobs/manage_subs.go +++ /dev/null @@ -1,362 +0,0 @@ -package eventstojobs - -import ( - "context" - "errors" - "fmt" - "io" - "sync" - "time" - - log "github.com/sirupsen/logrus" - "golang.org/x/sync/errgroup" - - "github.com/armadaproject/armada/internal/jobservice/events" - "github.com/armadaproject/armada/internal/jobservice/repository" - "github.com/armadaproject/armada/pkg/api" -) - -type JobSetSubscription struct { - repository.JobSetKey - - fromMessageId string - - sqlJobService repository.SQLJobService - eventReader events.JobEventReader - - ctx context.Context - cancel context.CancelFunc - - subTimeout time.Duration - - subDoneChan chan<- *repository.JobSetKey -} - -type JobSetSubscriptionExecutor struct { - ctx context.Context - - sqlJobService repository.SQLJobService - eventReader events.JobEventReader - - subscriptions map[repository.JobSetKey]*JobSetSubscription - mutex sync.Mutex - - newSubChan <-chan *repository.SubscribedTuple - subDoneChan chan *repository.JobSetKey - - subTimeout time.Duration -} - -func NewJobSetSubscriptionExecutor(ctx context.Context, - eventReader events.JobEventReader, - sqlJobService repository.SQLJobService, - newSubChan <-chan *repository.SubscribedTuple, - subTimeout time.Duration, -) *JobSetSubscriptionExecutor { - return &JobSetSubscriptionExecutor{ - ctx: ctx, - eventReader: eventReader, - sqlJobService: sqlJobService, - subscriptions: make(map[repository.JobSetKey]*JobSetSubscription), - newSubChan: newSubChan, - subDoneChan: make(chan *repository.JobSetKey, 1000), - subTimeout: subTimeout, - } -} - -func (jse *JobSetSubscriptionExecutor) Manage() { - go jse.ScanForMissingSubscriptions() - - // Main {un}subscribe loop. - for { - select { - case <-jse.ctx.Done(): - log.Debug("Context is done.") - return - case newSubInfo := <-jse.newSubChan: - jse.addSubscription(newSubInfo) - err := jse.launchSubscriber(&newSubInfo.JobSetKey) - if err != nil { - log.WithError(err).Error("JobSet subscribe error") - } - case subDoneKey := <-jse.subDoneChan: - log.Infof("Removing subscription on %s/%s", subDoneKey.Queue, subDoneKey.JobSetId) - err := jse.removeSubscription(subDoneKey) - if err != nil { - log.WithError(err).Error("JobSet unsubscribe error") - } - - } - } -} - -// Looks for subscriptions that show as active in the DB but are not active -// in this executor. -func (jse *JobSetSubscriptionExecutor) ScanForMissingSubscriptions() { - nextScan := time.After(1 * time.Nanosecond) - for { - select { - case <-jse.ctx.Done(): - return - case <-nextScan: - scanStart := time.Now() - - subscriptions, err := jse.sqlJobService.GetSubscribedJobSets(jse.ctx) - if err != nil { - log.WithError(err).Error("error getting subscribed job sets") - nextScan = time.After(60 * time.Second) - continue - } - - for _, sub := range subscriptions { - // Adding an already existing subscription is a no-op. - jse.addSubscription(&sub) - } - - scanEnd := time.Now() - duration := scanEnd.Sub(scanStart) - log.Infof("Scan for missing subs took %s", duration.String()) - log.Infof("There are %d active jobset subscriptions", jse.NumActiveSubscriptions()) - - nextScan = time.After(60 * time.Second) - } - } -} - -func (jse *JobSetSubscriptionExecutor) addSubscription(sub *repository.SubscribedTuple) { - jse.mutex.Lock() - defer jse.mutex.Unlock() - - _, ok := jse.subscriptions[sub.JobSetKey] - if ok { - // TODO: What to do if subscription already exists locally? - // Restart it? Do nothing? - } else { // sub doesn't already exist. - jse.subscriptions[sub.JobSetKey] = NewJobSetSubscription( - jse.ctx, - jse.eventReader, - sub, - jse.subTimeout, - jse.subDoneChan, - jse.sqlJobService) - - err := jse.sqlJobService.SubscribeJobSet(jse.ctx, sub.Queue, sub.JobSetId, sub.FromMessageId) - if err != nil { - log.Errorf("Could not add subscription on %s/%s to DB: %s", sub.Queue, sub.JobSetId, err.Error()) - } - } -} - -func (jse *JobSetSubscriptionExecutor) launchSubscriber(key *repository.JobSetKey) error { - jse.mutex.Lock() - sub, ok := jse.subscriptions[*key] - jse.mutex.Unlock() - - if ok { - go sub.Subscribe() //nolint:errcheck - return nil - } - return fmt.Errorf("No subscription with specified key %s/%s exists!", sub.Queue, sub.JobSetId) -} - -func (jse *JobSetSubscriptionExecutor) removeSubscription(key *repository.JobSetKey) error { - jse.mutex.Lock() - defer jse.mutex.Unlock() - - sub, ok := jse.subscriptions[*key] - if ok { - sub.cancel() - delete(jse.subscriptions, *key) - } else { - log.Errorf("No subscription with specified key %s/%s exists!", key.Queue, key.JobSetId) - } - - _, err := jse.sqlJobService.UnsubscribeJobSet(jse.ctx, key.Queue, key.JobSetId) - return err -} - -func (jse *JobSetSubscriptionExecutor) HasSubscription(key *repository.JobSetKey) bool { - jse.mutex.Lock() - defer jse.mutex.Unlock() - - _, ok := jse.subscriptions[*key] - return ok -} - -func (jse *JobSetSubscriptionExecutor) NumActiveSubscriptions() int { - jse.mutex.Lock() - defer jse.mutex.Unlock() - - return len(jse.subscriptions) -} - -func NewJobSetSubscription(ctx context.Context, - eventReader events.JobEventReader, - subInfo *repository.SubscribedTuple, - subTimeout time.Duration, - subDoneChan chan<- *repository.JobSetKey, - sqlJobService repository.SQLJobService, -) *JobSetSubscription { - newCtx, cancel := context.WithCancel(ctx) - return &JobSetSubscription{ - ctx: newCtx, - cancel: cancel, - eventReader: eventReader, - JobSetKey: subInfo.JobSetKey, - fromMessageId: subInfo.FromMessageId, - subTimeout: subTimeout, - subDoneChan: subDoneChan, - sqlJobService: sqlJobService, - } -} - -func (js *JobSetSubscription) Subscribe() error { - requestFields := log.Fields{ - "job_set_id": js.JobSetId, - "queue": js.Queue, - "from_message_id": js.fromMessageId, - } - - defer func() { - js.subDoneChan <- &repository.JobSetKey{ - Queue: js.Queue, - JobSetId: js.JobSetId, - } - log.WithFields(requestFields).Debugf("Sent message to subDoneChan") - }() - - log.WithFields(requestFields).Debugf("Calling GetJobEventMessage") - - stream, err := js.eventReader.GetJobEventMessage(js.ctx, &api.JobSetRequest{ - Id: js.JobSetId, - Queue: js.Queue, - Watch: true, - FromMessageId: js.fromMessageId, - }) - if err != nil { - log.WithFields(requestFields).WithError(err).Error("error from GetJobEventMessage") - return err - } - - log.WithFields(requestFields).Debug("Got stream") - - g, _ := errgroup.WithContext(js.ctx) - - // Subscription status check ticker. - timeout := time.NewTicker(js.subTimeout) - - g.Go(func() error { - for { - select { - case <-js.ctx.Done(): - return nil - case <-timeout.C: - log.WithFields(requestFields).Debug("JobSetSubscription.Subscribe checking subscription status") - // Stream is created with *our* context, therefore if we cancel, stream.Recv() should bail out too. - unsub, err := js.sqlJobService.CheckToUnSubscribe(js.ctx, js.Queue, js.JobSetId, js.subTimeout) - if err != nil { - log.WithFields(requestFields).WithError(err).Error("IsJobSetSubscribed error") - } - // We should unsubscribe - if unsub { - log.WithFields(requestFields).Info("subscription done") - js.cancel() - return nil - } - } - } - }) - - // Nanosecond, zero wait essentially. - g.Go(func() error { - nextRecv := time.After(1 * time.Nanosecond) - - defer func() { - js.cancel() - log.WithFields(requestFields).Debugf("Called cancel") - }() - - shouldReconnect := false - - // this loop will run until the context is canceled - for { - select { - case <-js.ctx.Done(): - log.WithFields(requestFields).Debug("context is done") - return nil - case <-nextRecv: - - if shouldReconnect { - stream, err = js.eventReader.GetJobEventMessage(js.ctx, &api.JobSetRequest{ - Id: js.JobSetId, - Queue: js.Queue, - Watch: true, - FromMessageId: js.fromMessageId, - }) - // Treat stream creation errors as terminal, like we do in Subscribe() - if err != nil { - log.WithFields(requestFields).WithError(err).Error("error from GetJobEventMessage") - return err - } - - shouldReconnect = false - } - - msg, err := stream.Recv() - if err != nil { - if err == io.EOF { - log.WithFields(requestFields).Info("Reached stream end for JobSetSubscription") - return nil - } else if errors.Is(err, context.Canceled) { - // The select case will handle context being done/canceled. - continue - } - - log.WithFields(requestFields).WithError(err).Error("could not obtain job set event message, retrying") - settingSubscribeErr := js.sqlJobService.SetSubscriptionError( - js.ctx, js.Queue, js.JobSetId, err.Error(), js.fromMessageId) - if settingSubscribeErr != nil { - log.WithFields(requestFields).WithError(settingSubscribeErr).Error("could not set error field in job set table") - } - nextRecv = time.After(5 * time.Second) - // Consider this stream dead - shouldReconnect = true - continue - } - - errClear := js.sqlJobService.AddMessageIdAndClearSubscriptionError( - js.ctx, js.Queue, js.JobSetId, js.fromMessageId) - if errClear != nil { - log.WithFields(requestFields).WithError(errClear).Error("could not clear subscription error from job set table") - } - currentJobId := api.JobIdFromApiEvent(msg.Message) - jobStatus := EventsToJobResponse(*msg.Message) - if jobStatus != nil { - log.WithFields(requestFields).WithFields(log.Fields{ - "job_id": currentJobId, - "job_status": jobStatus.GetState().String(), - }).Debug("Got event") - jobStatus := repository.NewJobStatus(js.Queue, js.JobSetId, currentJobId, *jobStatus) - err := js.sqlJobService.UpdateJobServiceDb(js.ctx, jobStatus) - if err != nil { - log.WithFields(requestFields).WithError(err).Error("could not update job status, retrying") - nextRecv = time.After(5 * time.Second) - continue - } - } else { - log.WithFields(requestFields).WithFields(log.Fields{ - "job_id": currentJobId, - "message": msg.Message, - }).Debug("Got non-status event") - } - // advance the message id for next loop - js.fromMessageId = msg.GetId() - requestFields["from_message_id"] = js.fromMessageId - // Nanosecond, essentially go again now. - nextRecv = time.After(1 * time.Nanosecond) - } - } - }) - - return g.Wait() -} diff --git a/internal/jobservice/eventstojobs/manage_subs_test.go b/internal/jobservice/eventstojobs/manage_subs_test.go deleted file mode 100644 index 77d1f842464..00000000000 --- a/internal/jobservice/eventstojobs/manage_subs_test.go +++ /dev/null @@ -1,251 +0,0 @@ -package eventstojobs - -import ( - "context" - "errors" - "fmt" - "io" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "google.golang.org/grpc/metadata" - - "github.com/armadaproject/armada/internal/jobservice/events" - "github.com/armadaproject/armada/internal/jobservice/repository" - "github.com/armadaproject/armada/pkg/api" -) - -type MockEventClient struct { - eventStreamMessage *api.EventStreamMessage - messagesSent int - err error -} - -func (m *MockEventClient) Recv() (*api.EventStreamMessage, error) { - msg := m.eventStreamMessage - if msg == nil { - msg = &api.EventStreamMessage{ - Id: "msgID", - Message: &api.EventMessage{}, - } - m.eventStreamMessage = msg - m.messagesSent = 0 - } - - m.messagesSent += 1 - - if m.messagesSent > 3 { - // Sleep a bit to mimick the stream being open but no events - // currently available. - time.Sleep(time.Second * 5) - return nil, io.EOF - } - - // Always return the error, they are terminal - return msg, m.err -} - -func (m *MockEventClient) CloseSend() error { - return nil -} - -func (m *MockEventClient) Context() context.Context { - return context.Background() -} - -func (m *MockEventClient) Header() (metadata.MD, error) { - return metadata.MD{}, nil -} - -func (m *MockEventClient) Trailer() metadata.MD { - return metadata.MD{} -} - -func (m *MockEventClient) SendMsg(msg interface{}) error { - return nil -} - -func (m *MockEventClient) RecvMsg(msg interface{}) error { - return nil -} - -func TestJobSetSubscriptionSubscribe(t *testing.T) { - tests := []struct { - name string - isJobSetSubscribedFn func(context.Context, string, string) (bool, string, error) - ttlSecs time.Duration - eventClients []MockEventClient - wantErr bool - wantSubscriptionErr bool - }{ - { - name: "no error after expiration if messages are received", - ttlSecs: time.Second, - eventClients: []MockEventClient{{}}, - isJobSetSubscribedFn: func(context.Context, string, string) (bool, string, error) { - return true, "", nil - }, - wantErr: false, - }, - { - name: "client errors and sets subscription error, reconnects to continue on and exit normally", - ttlSecs: time.Second * 10, - eventClients: []MockEventClient{{err: errors.New("some error")}, {}}, - isJobSetSubscribedFn: func(context.Context, string, string) (bool, string, error) { - return true, "", nil - }, - wantErr: false, - wantSubscriptionErr: true, - }, - { - name: "it exits without error when job unsubscribes", - ttlSecs: time.Second, - eventClients: []MockEventClient{{}}, - isJobSetSubscribedFn: func(context.Context, string, string) (bool, string, error) { - return false, "", nil - }, - wantErr: false, - }, - } - - subDoneChan := make(chan *repository.JobSetKey, 5) - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - eventClientIndex := 0 - getEventClientFun := func(ctx context.Context, jobReq *api.JobSetRequest) (api.Event_GetJobSetEventsClient, error) { - eventClient := tt.eventClients[eventClientIndex] - eventClientIndex++ - return &eventClient, nil - } - - mockJobEventReader := events.JobEventReaderMock{ - GetJobEventMessageFunc: getEventClientFun, - CloseFunc: func() {}, - } - - mockJobRepo := repository.SQLJobServiceMock{ - IsJobSetSubscribedFunc: tt.isJobSetSubscribedFn, - SubscribeJobSetFunc: func(context.Context, string, string, string) error { return nil }, - AddMessageIdAndClearSubscriptionErrorFunc: func(context.Context, string, string, string) error { return nil }, - SetSubscriptionErrorFunc: func(context.Context, string, string, string, string) error { return nil }, - UnsubscribeJobSetFunc: func(context.Context, string, string) (int64, error) { return 0, nil }, - CheckToUnSubscribeFunc: func(context.Context, string, string, time.Duration) (bool, error) { return true, nil }, - GetSubscribedJobSetsFunc: func(context.Context) ([]repository.SubscribedTuple, error) { - return make([]repository.SubscribedTuple, 0), nil - }, - } - - subInfo := &repository.SubscribedTuple{ - JobSetKey: repository.JobSetKey{ - Queue: "testQueue", - JobSetId: "testID", - }, - } - - sub := NewJobSetSubscription( - context.Background(), - &mockJobEventReader, - subInfo, - tt.ttlSecs, - subDoneChan, - &mockJobRepo, - ) - - result := sub.Subscribe() - - key := <-subDoneChan - assert.Equal(t, key.Queue, "testQueue") - assert.Equal(t, key.JobSetId, "testID") - - if tt.wantErr { - assert.Error(t, result) - } else { - assert.Nil(t, result) - } - if tt.wantSubscriptionErr { - assert.True(t, len(mockJobRepo.SetSubscriptionErrorCalls()) > 0) - assert.Equal(t, 3, len(mockJobRepo.AddMessageIdAndClearSubscriptionErrorCalls())) - } else { - assert.Equal(t, 0, len(mockJobRepo.SetSubscriptionErrorCalls())) - assert.True(t, len(mockJobRepo.AddMessageIdAndClearSubscriptionErrorCalls()) > 0) - } - }) - } -} - -// Tests general function of the subscription executor. -func TestJobSetSubscriptionExecutor(t *testing.T) { - eventClient := MockEventClient{ - err: nil, - } - - mockJobEventReader := events.JobEventReaderMock{ - GetJobEventMessageFunc: func(context.Context, *api.JobSetRequest) (api.Event_GetJobSetEventsClient, error) { - return &eventClient, nil - }, - CloseFunc: func() {}, - } - - ctx := context.Background() - - mockJobRepo := repository.SQLJobServiceMock{ - IsJobSetSubscribedFunc: func(context.Context, string, string) (bool, string, error) { return true, "", nil }, - SubscribeJobSetFunc: func(context.Context, string, string, string) error { return nil }, - AddMessageIdAndClearSubscriptionErrorFunc: func(context.Context, string, string, string) error { return nil }, - SetSubscriptionErrorFunc: func(context.Context, string, string, string, string) error { return nil }, - UnsubscribeJobSetFunc: func(context.Context, string, string) (int64, error) { return 0, nil }, - CheckToUnSubscribeFunc: func(context.Context, string, string, time.Duration) (bool, error) { return true, nil }, - GetSubscribedJobSetsFunc: func(context.Context) ([]repository.SubscribedTuple, error) { - return make([]repository.SubscribedTuple, 0), nil - }, - } - - jobSubChan := make(chan *repository.SubscribedTuple, 10) - - executor := NewJobSetSubscriptionExecutor( - ctx, - &mockJobEventReader, - &mockJobRepo, - jobSubChan, - time.Second, - ) - - go executor.Manage() - - for i := 0; i < 5; i++ { - jobSubChan <- &repository.SubscribedTuple{ - JobSetKey: repository.JobSetKey{ - Queue: fmt.Sprintf("TestQueue-%d", i), - JobSetId: fmt.Sprintf("TestJobSetId-%d", i), - }, - } - } - - // Wait for all subs to clear. - sawSubs := false - numberSeen := 0 - func() { - watchDog := time.After(time.Second * 10) - ticker := time.NewTicker(time.Millisecond * 200) - for { - select { - case <-ticker.C: - numSubs := executor.NumActiveSubscriptions() - if numSubs == 0 { - return - } else if !sawSubs { - sawSubs = true - numberSeen = numSubs - } - case <-watchDog: - assert.True(t, false, "Reached time out waiting for subscriptions to clear") - return - } - } - }() - - assert.True(t, sawSubs, "Never saw the executor handle any subscriptions") - assert.Equal(t, numberSeen, 5, "Didn't see the expected amount of subscriptions") -} diff --git a/internal/jobservice/repository/job_status.go b/internal/jobservice/repository/job_status.go deleted file mode 100644 index bd04158107c..00000000000 --- a/internal/jobservice/repository/job_status.go +++ /dev/null @@ -1,21 +0,0 @@ -package repository - -import ( - "time" - - js "github.com/armadaproject/armada/pkg/api/jobservice" -) - -// JobStatus represents a job status -type JobStatus struct { - queue string - jobSetId string - jobId string - jobResponse js.JobServiceResponse - timeStamp int64 -} - -// NewJobStatus combines params into struct JobStatus and adds a timestamp -func NewJobStatus(queue string, jobSetId string, jobId string, jobResponse js.JobServiceResponse) *JobStatus { - return &JobStatus{queue: queue, jobSetId: jobSetId, jobId: jobId, jobResponse: jobResponse, timeStamp: time.Now().Unix()} -} diff --git a/internal/jobservice/repository/job_status_test.go b/internal/jobservice/repository/job_status_test.go deleted file mode 100644 index 7220b0202d4..00000000000 --- a/internal/jobservice/repository/job_status_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package repository - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/armadaproject/armada/pkg/api/jobservice" -) - -func TestJobTable(t *testing.T) { - jobStatus := NewJobStatus("test-queue", "test-job-set", "test-job-id", jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_JOB_ID_NOT_FOUND}) - assert.Equal(t, jobStatus.queue, "test-queue") - assert.Equal(t, jobStatus.jobSetId, "test-job-set") - assert.Equal(t, jobStatus.jobId, "test-job-id") - assert.Equal(t, jobStatus.jobResponse, jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_JOB_ID_NOT_FOUND}) - assert.True(t, jobStatus.timeStamp > 0) -} diff --git a/internal/jobservice/repository/job_table_updater_moq.go b/internal/jobservice/repository/job_table_updater_moq.go deleted file mode 100644 index c16330179e5..00000000000 --- a/internal/jobservice/repository/job_table_updater_moq.go +++ /dev/null @@ -1,547 +0,0 @@ -// Code generated by moq; DO NOT EDIT. -// github.com/matryer/moq - -package repository - -import ( - "context" - "sync" -) - -// Ensure, that JobTableUpdaterMock does implement JobTableUpdater. -// If this is not the case, regenerate this file with moq. -var _ JobTableUpdater = &JobTableUpdaterMock{} - -// JobTableUpdaterMock is a mock implementation of JobTableUpdater. -// -// func TestSomethingThatUsesJobTableUpdater(t *testing.T) { -// -// // make and configure a mocked JobTableUpdater -// mockedJobTableUpdater := &JobTableUpdaterMock{ -// AddMessageIdAndClearSubscriptionErrorFunc: func(ctx context.Context, queue string, jobSet string, messageId string) error { -// panic("mock out the AddMessageIdAndClearSubscriptionError method") -// }, -// GetSubscribedJobSetsFunc: func(ctx context.Context) ([]SubscribedTuple, error) { -// panic("mock out the GetSubscribedJobSets method") -// }, -// GetSubscriptionErrorFunc: func(ctx context.Context, queue string, jobSet string) (string, error) { -// panic("mock out the GetSubscriptionError method") -// }, -// IsJobSetSubscribedFunc: func(ctx context.Context, queue string, jobSet string) (bool, string, error) { -// panic("mock out the IsJobSetSubscribed method") -// }, -// SetSubscriptionErrorFunc: func(ctx context.Context, queue string, jobSet string, err string, fromMessageId string) error { -// panic("mock out the SetSubscriptionError method") -// }, -// SubscribeJobSetFunc: func(ctx context.Context, queue string, jobSet string, fromMessageId string) error { -// panic("mock out the SubscribeJobSet method") -// }, -// UnsubscribeJobSetFunc: func(ctx context.Context, queue string, jobSet string) (int64, error) { -// panic("mock out the UnsubscribeJobSet method") -// }, -// UpdateJobServiceDbFunc: func(ctx context.Context, jobTable *JobStatus) error { -// panic("mock out the UpdateJobServiceDb method") -// }, -// UpdateJobSetDbFunc: func(ctx context.Context, queue string, jobSet string, fromMessageId string) error { -// panic("mock out the UpdateJobSetDb method") -// }, -// } -// -// // use mockedJobTableUpdater in code that requires JobTableUpdater -// // and then make assertions. -// -// } -type JobTableUpdaterMock struct { - // AddMessageIdAndClearSubscriptionErrorFunc mocks the AddMessageIdAndClearSubscriptionError method. - AddMessageIdAndClearSubscriptionErrorFunc func(ctx context.Context, queue string, jobSet string, messageId string) error - - // GetSubscribedJobSetsFunc mocks the GetSubscribedJobSets method. - GetSubscribedJobSetsFunc func(ctx context.Context) ([]SubscribedTuple, error) - - // GetSubscriptionErrorFunc mocks the GetSubscriptionError method. - GetSubscriptionErrorFunc func(ctx context.Context, queue string, jobSet string) (string, error) - - // IsJobSetSubscribedFunc mocks the IsJobSetSubscribed method. - IsJobSetSubscribedFunc func(ctx context.Context, queue string, jobSet string) (bool, string, error) - - // SetSubscriptionErrorFunc mocks the SetSubscriptionError method. - SetSubscriptionErrorFunc func(ctx context.Context, queue string, jobSet string, err string, fromMessageId string) error - - // SubscribeJobSetFunc mocks the SubscribeJobSet method. - SubscribeJobSetFunc func(ctx context.Context, queue string, jobSet string, fromMessageId string) error - - // UnsubscribeJobSetFunc mocks the UnsubscribeJobSet method. - UnsubscribeJobSetFunc func(ctx context.Context, queue string, jobSet string) (int64, error) - - // UpdateJobServiceDbFunc mocks the UpdateJobServiceDb method. - UpdateJobServiceDbFunc func(ctx context.Context, jobTable *JobStatus) error - - // UpdateJobSetDbFunc mocks the UpdateJobSetDb method. - UpdateJobSetDbFunc func(ctx context.Context, queue string, jobSet string, fromMessageId string) error - - // calls tracks calls to the methods. - calls struct { - // AddMessageIdAndClearSubscriptionError holds details about calls to the AddMessageIdAndClearSubscriptionError method. - AddMessageIdAndClearSubscriptionError []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // MessageId is the messageId argument value. - MessageId string - } - // GetSubscribedJobSets holds details about calls to the GetSubscribedJobSets method. - GetSubscribedJobSets []struct { - // Ctx is the ctx argument value. - Ctx context.Context - } - // GetSubscriptionError holds details about calls to the GetSubscriptionError method. - GetSubscriptionError []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - } - // IsJobSetSubscribed holds details about calls to the IsJobSetSubscribed method. - IsJobSetSubscribed []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - } - // SetSubscriptionError holds details about calls to the SetSubscriptionError method. - SetSubscriptionError []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // Err is the err argument value. - Err string - // FromMessageId is the fromMessageId argument value. - FromMessageId string - } - // SubscribeJobSet holds details about calls to the SubscribeJobSet method. - SubscribeJobSet []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // FromMessageId is the fromMessageId argument value. - FromMessageId string - } - // UnsubscribeJobSet holds details about calls to the UnsubscribeJobSet method. - UnsubscribeJobSet []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - } - // UpdateJobServiceDb holds details about calls to the UpdateJobServiceDb method. - UpdateJobServiceDb []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // JobTable is the jobTable argument value. - JobTable *JobStatus - } - // UpdateJobSetDb holds details about calls to the UpdateJobSetDb method. - UpdateJobSetDb []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // FromMessageId is the fromMessageId argument value. - FromMessageId string - } - } - lockAddMessageIdAndClearSubscriptionError sync.RWMutex - lockGetSubscribedJobSets sync.RWMutex - lockGetSubscriptionError sync.RWMutex - lockIsJobSetSubscribed sync.RWMutex - lockSetSubscriptionError sync.RWMutex - lockSubscribeJobSet sync.RWMutex - lockUnsubscribeJobSet sync.RWMutex - lockUpdateJobServiceDb sync.RWMutex - lockUpdateJobSetDb sync.RWMutex -} - -// AddMessageIdAndClearSubscriptionError calls AddMessageIdAndClearSubscriptionErrorFunc. -func (mock *JobTableUpdaterMock) AddMessageIdAndClearSubscriptionError(ctx context.Context, queue string, jobSet string, messageId string) error { - if mock.AddMessageIdAndClearSubscriptionErrorFunc == nil { - panic("JobTableUpdaterMock.AddMessageIdAndClearSubscriptionErrorFunc: method is nil but JobTableUpdater.AddMessageIdAndClearSubscriptionError was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - MessageId string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - MessageId: messageId, - } - mock.lockAddMessageIdAndClearSubscriptionError.Lock() - mock.calls.AddMessageIdAndClearSubscriptionError = append(mock.calls.AddMessageIdAndClearSubscriptionError, callInfo) - mock.lockAddMessageIdAndClearSubscriptionError.Unlock() - return mock.AddMessageIdAndClearSubscriptionErrorFunc(ctx, queue, jobSet, messageId) -} - -// AddMessageIdAndClearSubscriptionErrorCalls gets all the calls that were made to AddMessageIdAndClearSubscriptionError. -// Check the length with: -// -// len(mockedJobTableUpdater.AddMessageIdAndClearSubscriptionErrorCalls()) -func (mock *JobTableUpdaterMock) AddMessageIdAndClearSubscriptionErrorCalls() []struct { - Ctx context.Context - Queue string - JobSet string - MessageId string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - MessageId string - } - mock.lockAddMessageIdAndClearSubscriptionError.RLock() - calls = mock.calls.AddMessageIdAndClearSubscriptionError - mock.lockAddMessageIdAndClearSubscriptionError.RUnlock() - return calls -} - -// GetSubscribedJobSets calls GetSubscribedJobSetsFunc. -func (mock *JobTableUpdaterMock) GetSubscribedJobSets(ctx context.Context) ([]SubscribedTuple, error) { - if mock.GetSubscribedJobSetsFunc == nil { - panic("JobTableUpdaterMock.GetSubscribedJobSetsFunc: method is nil but JobTableUpdater.GetSubscribedJobSets was just called") - } - callInfo := struct { - Ctx context.Context - }{ - Ctx: ctx, - } - mock.lockGetSubscribedJobSets.Lock() - mock.calls.GetSubscribedJobSets = append(mock.calls.GetSubscribedJobSets, callInfo) - mock.lockGetSubscribedJobSets.Unlock() - return mock.GetSubscribedJobSetsFunc(ctx) -} - -// GetSubscribedJobSetsCalls gets all the calls that were made to GetSubscribedJobSets. -// Check the length with: -// -// len(mockedJobTableUpdater.GetSubscribedJobSetsCalls()) -func (mock *JobTableUpdaterMock) GetSubscribedJobSetsCalls() []struct { - Ctx context.Context -} { - var calls []struct { - Ctx context.Context - } - mock.lockGetSubscribedJobSets.RLock() - calls = mock.calls.GetSubscribedJobSets - mock.lockGetSubscribedJobSets.RUnlock() - return calls -} - -// GetSubscriptionError calls GetSubscriptionErrorFunc. -func (mock *JobTableUpdaterMock) GetSubscriptionError(ctx context.Context, queue string, jobSet string) (string, error) { - if mock.GetSubscriptionErrorFunc == nil { - panic("JobTableUpdaterMock.GetSubscriptionErrorFunc: method is nil but JobTableUpdater.GetSubscriptionError was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - } - mock.lockGetSubscriptionError.Lock() - mock.calls.GetSubscriptionError = append(mock.calls.GetSubscriptionError, callInfo) - mock.lockGetSubscriptionError.Unlock() - return mock.GetSubscriptionErrorFunc(ctx, queue, jobSet) -} - -// GetSubscriptionErrorCalls gets all the calls that were made to GetSubscriptionError. -// Check the length with: -// -// len(mockedJobTableUpdater.GetSubscriptionErrorCalls()) -func (mock *JobTableUpdaterMock) GetSubscriptionErrorCalls() []struct { - Ctx context.Context - Queue string - JobSet string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - } - mock.lockGetSubscriptionError.RLock() - calls = mock.calls.GetSubscriptionError - mock.lockGetSubscriptionError.RUnlock() - return calls -} - -// IsJobSetSubscribed calls IsJobSetSubscribedFunc. -func (mock *JobTableUpdaterMock) IsJobSetSubscribed(ctx context.Context, queue string, jobSet string) (bool, string, error) { - if mock.IsJobSetSubscribedFunc == nil { - panic("JobTableUpdaterMock.IsJobSetSubscribedFunc: method is nil but JobTableUpdater.IsJobSetSubscribed was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - } - mock.lockIsJobSetSubscribed.Lock() - mock.calls.IsJobSetSubscribed = append(mock.calls.IsJobSetSubscribed, callInfo) - mock.lockIsJobSetSubscribed.Unlock() - return mock.IsJobSetSubscribedFunc(ctx, queue, jobSet) -} - -// IsJobSetSubscribedCalls gets all the calls that were made to IsJobSetSubscribed. -// Check the length with: -// -// len(mockedJobTableUpdater.IsJobSetSubscribedCalls()) -func (mock *JobTableUpdaterMock) IsJobSetSubscribedCalls() []struct { - Ctx context.Context - Queue string - JobSet string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - } - mock.lockIsJobSetSubscribed.RLock() - calls = mock.calls.IsJobSetSubscribed - mock.lockIsJobSetSubscribed.RUnlock() - return calls -} - -// SetSubscriptionError calls SetSubscriptionErrorFunc. -func (mock *JobTableUpdaterMock) SetSubscriptionError(ctx context.Context, queue string, jobSet string, err string, fromMessageId string) error { - if mock.SetSubscriptionErrorFunc == nil { - panic("JobTableUpdaterMock.SetSubscriptionErrorFunc: method is nil but JobTableUpdater.SetSubscriptionError was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - Err string - FromMessageId string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - Err: err, - FromMessageId: fromMessageId, - } - mock.lockSetSubscriptionError.Lock() - mock.calls.SetSubscriptionError = append(mock.calls.SetSubscriptionError, callInfo) - mock.lockSetSubscriptionError.Unlock() - return mock.SetSubscriptionErrorFunc(ctx, queue, jobSet, err, fromMessageId) -} - -// SetSubscriptionErrorCalls gets all the calls that were made to SetSubscriptionError. -// Check the length with: -// -// len(mockedJobTableUpdater.SetSubscriptionErrorCalls()) -func (mock *JobTableUpdaterMock) SetSubscriptionErrorCalls() []struct { - Ctx context.Context - Queue string - JobSet string - Err string - FromMessageId string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - Err string - FromMessageId string - } - mock.lockSetSubscriptionError.RLock() - calls = mock.calls.SetSubscriptionError - mock.lockSetSubscriptionError.RUnlock() - return calls -} - -// SubscribeJobSet calls SubscribeJobSetFunc. -func (mock *JobTableUpdaterMock) SubscribeJobSet(ctx context.Context, queue string, jobSet string, fromMessageId string) error { - if mock.SubscribeJobSetFunc == nil { - panic("JobTableUpdaterMock.SubscribeJobSetFunc: method is nil but JobTableUpdater.SubscribeJobSet was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - FromMessageId: fromMessageId, - } - mock.lockSubscribeJobSet.Lock() - mock.calls.SubscribeJobSet = append(mock.calls.SubscribeJobSet, callInfo) - mock.lockSubscribeJobSet.Unlock() - return mock.SubscribeJobSetFunc(ctx, queue, jobSet, fromMessageId) -} - -// SubscribeJobSetCalls gets all the calls that were made to SubscribeJobSet. -// Check the length with: -// -// len(mockedJobTableUpdater.SubscribeJobSetCalls()) -func (mock *JobTableUpdaterMock) SubscribeJobSetCalls() []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - } - mock.lockSubscribeJobSet.RLock() - calls = mock.calls.SubscribeJobSet - mock.lockSubscribeJobSet.RUnlock() - return calls -} - -// UnsubscribeJobSet calls UnsubscribeJobSetFunc. -func (mock *JobTableUpdaterMock) UnsubscribeJobSet(ctx context.Context, queue string, jobSet string) (int64, error) { - if mock.UnsubscribeJobSetFunc == nil { - panic("JobTableUpdaterMock.UnsubscribeJobSetFunc: method is nil but JobTableUpdater.UnsubscribeJobSet was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - } - mock.lockUnsubscribeJobSet.Lock() - mock.calls.UnsubscribeJobSet = append(mock.calls.UnsubscribeJobSet, callInfo) - mock.lockUnsubscribeJobSet.Unlock() - return mock.UnsubscribeJobSetFunc(ctx, queue, jobSet) -} - -// UnsubscribeJobSetCalls gets all the calls that were made to UnsubscribeJobSet. -// Check the length with: -// -// len(mockedJobTableUpdater.UnsubscribeJobSetCalls()) -func (mock *JobTableUpdaterMock) UnsubscribeJobSetCalls() []struct { - Ctx context.Context - Queue string - JobSet string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - } - mock.lockUnsubscribeJobSet.RLock() - calls = mock.calls.UnsubscribeJobSet - mock.lockUnsubscribeJobSet.RUnlock() - return calls -} - -// UpdateJobServiceDb calls UpdateJobServiceDbFunc. -func (mock *JobTableUpdaterMock) UpdateJobServiceDb(ctx context.Context, jobTable *JobStatus) error { - if mock.UpdateJobServiceDbFunc == nil { - panic("JobTableUpdaterMock.UpdateJobServiceDbFunc: method is nil but JobTableUpdater.UpdateJobServiceDb was just called") - } - callInfo := struct { - Ctx context.Context - JobTable *JobStatus - }{ - Ctx: ctx, - JobTable: jobTable, - } - mock.lockUpdateJobServiceDb.Lock() - mock.calls.UpdateJobServiceDb = append(mock.calls.UpdateJobServiceDb, callInfo) - mock.lockUpdateJobServiceDb.Unlock() - return mock.UpdateJobServiceDbFunc(ctx, jobTable) -} - -// UpdateJobServiceDbCalls gets all the calls that were made to UpdateJobServiceDb. -// Check the length with: -// -// len(mockedJobTableUpdater.UpdateJobServiceDbCalls()) -func (mock *JobTableUpdaterMock) UpdateJobServiceDbCalls() []struct { - Ctx context.Context - JobTable *JobStatus -} { - var calls []struct { - Ctx context.Context - JobTable *JobStatus - } - mock.lockUpdateJobServiceDb.RLock() - calls = mock.calls.UpdateJobServiceDb - mock.lockUpdateJobServiceDb.RUnlock() - return calls -} - -// UpdateJobSetDb calls UpdateJobSetDbFunc. -func (mock *JobTableUpdaterMock) UpdateJobSetDb(ctx context.Context, queue string, jobSet string, fromMessageId string) error { - if mock.UpdateJobSetDbFunc == nil { - panic("JobTableUpdaterMock.UpdateJobSetDbFunc: method is nil but JobTableUpdater.UpdateJobSetDb was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - FromMessageId: fromMessageId, - } - mock.lockUpdateJobSetDb.Lock() - mock.calls.UpdateJobSetDb = append(mock.calls.UpdateJobSetDb, callInfo) - mock.lockUpdateJobSetDb.Unlock() - return mock.UpdateJobSetDbFunc(ctx, queue, jobSet, fromMessageId) -} - -// UpdateJobSetDbCalls gets all the calls that were made to UpdateJobSetDb. -// Check the length with: -// -// len(mockedJobTableUpdater.UpdateJobSetDbCalls()) -func (mock *JobTableUpdaterMock) UpdateJobSetDbCalls() []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - } - mock.lockUpdateJobSetDb.RLock() - calls = mock.calls.UpdateJobSetDb - mock.lockUpdateJobSetDb.RUnlock() - return calls -} diff --git a/internal/jobservice/repository/postgres.go b/internal/jobservice/repository/postgres.go deleted file mode 100644 index 0b8a81b5cb6..00000000000 --- a/internal/jobservice/repository/postgres.go +++ /dev/null @@ -1,337 +0,0 @@ -package repository - -import ( - "context" - "fmt" - "time" - - _ "modernc.org/sqlite" - - "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgxpool" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" - - "github.com/armadaproject/armada/internal/common/database" - "github.com/armadaproject/armada/internal/jobservice/configuration" - js "github.com/armadaproject/armada/pkg/api/jobservice" -) - -type JSRepoPostgres struct { - jobServiceConfig *configuration.JobServiceConfiguration - dbpool *pgxpool.Pool -} - -func NewJSRepoPostgres(cfg *configuration.JobServiceConfiguration, log *log.Entry) (error, *JSRepoPostgres, func()) { - poolCfg, err := pgxpool.ParseConfig(database.CreateConnectionString(cfg.PostgresConfig.Connection)) - if err != nil { - return errors.Wrap(err, "cannot parse Postgres connection config"), nil, func() {} - } - - pool, err := pgxpool.NewWithConfig(context.Background(), poolCfg) - if err != nil { - return errors.Wrap(err, "cannot create Postgres connection pool"), nil, func() {} - } - - return nil, &JSRepoPostgres{jobServiceConfig: cfg, dbpool: pool}, func() {} -} - -// Set up the DB for use, create tables -func (s *JSRepoPostgres) Setup(ctx context.Context) { - setupStmts := []string{ - `DROP TABLE IF EXISTS jobs`, - `DROP INDEX IF EXISTS idx_job_set_queue`, - `DROP TABLE IF EXISTS jobsets`, - `CREATE TABLE jobsets ( - Queue TEXT, - Id TEXT, - Timestamp INTEGER, - ConnectionError TEXT, - FromMessageId TEXT, - UNIQUE (Id), - PRIMARY KEY (Queue, Id))`, - `CREATE INDEX idx_jobsets_timestamp ON jobsets (Timestamp)`, - `CREATE TABLE jobs ( - Queue TEXT, - JobSetId TEXT, - Id TEXT, - JobResponseState TEXT, - JobResponseError TEXT, - Timestamp INTEGER, - PRIMARY KEY(Id))`, - `CREATE INDEX idx_job_set_queue ON jobs (Queue, JobSetId)`, - `CREATE INDEX idx_jobs_timestamp ON jobs (Timestamp)`, - `DROP TRIGGER IF EXISTS trigger_delete_expired_jobsets ON jobsets`, - `DROP FUNCTION IF EXISTS delete_expired_jobsets`, - } - - for _, stmt := range setupStmts { - _, err := s.dbpool.Exec(ctx, stmt) - if err != nil { - panic(err) - } - } -} - -// Get the JobStatus given the jodId -func (s *JSRepoPostgres) GetJobStatus(ctx context.Context, jobId string) (*js.JobServiceResponse, error) { - sqlStmt := "SELECT Queue, JobSetId, JobResponseState, JobResponseError FROM jobs WHERE Id = $1" - - row := s.dbpool.QueryRow(ctx, sqlStmt, jobId) - var queue, jobSetId, jobState, jobError string - - err := row.Scan(&queue, &jobSetId, &jobState, &jobError) - - if err == pgx.ErrNoRows { - return &js.JobServiceResponse{State: js.JobServiceResponse_JOB_ID_NOT_FOUND}, nil - } else if err != nil { - return nil, err - } - - // indicate connnection error for jobset/queue subscription where present - connErr, err := s.GetSubscriptionError(ctx, queue, jobSetId) - if err != nil { - return nil, err - } - if connErr != "" { - return &js.JobServiceResponse{ - Error: connErr, - State: js.JobServiceResponse_CONNECTION_ERR, - }, nil - } - - jobJSRState, err := JobStateStrToJSRState(jobState) - if err != nil { - return nil, err - } - - return &js.JobServiceResponse{ - Error: jobError, - State: jobJSRState, - }, nil -} - -// Update database with JobTable. -func (s *JSRepoPostgres) UpdateJobServiceDb(ctx context.Context, jobTable *JobStatus) error { - sqlStmt := `INSERT INTO jobs (Queue, JobSetId, Id, JobResponseState, JobResponseError, Timestamp) - VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (Id) DO UPDATE SET - (Queue, JobSetId, JobResponseState, JobResponseError, Timestamp) = - (excluded.Queue, excluded.JobSetId, excluded.JobResponseState, excluded.JobResponseError, excluded.Timestamp)` - - _, errExec := s.dbpool.Exec(ctx, sqlStmt, jobTable.queue, jobTable.jobSetId, jobTable.jobId, - jobTable.jobResponse.State.String(), jobTable.jobResponse.Error, jobTable.timeStamp) - return errExec -} - -// We should check if a JobSet exists first before updating the database and return an error if it doesn't exist -// However, The only caller of this function, in jobservice/server/server.go, does this check before calling. -// Adding the check here will be redundant and a performance botteneck. -// TODO: We should descend the check here and adjust the JobSet subscription logic in jobservice/server/server.go -func (s *JSRepoPostgres) UpdateJobSetDb(ctx context.Context, queue string, jobSet string, fromMessageId string) error { - sqlStmt := `INSERT INTO jobsets (Queue, Id, Timestamp, ConnectionError, FromMessageId) - VALUES ($1, $2, $3, $4, $5) ON CONFLICT (Queue, Id) DO UPDATE SET - (Timestamp, ConnectionError, FromMessageId) = - (excluded.Timestamp, excluded.ConnectionError, excluded.FromMessageId)` - - _, jobSetErr := s.dbpool.Exec(ctx, sqlStmt, queue, jobSet, time.Now().Unix(), "", &fromMessageId) - if jobSetErr != nil { - return jobSetErr - } - return nil -} - -func (s *JSRepoPostgres) HealthCheck(ctx context.Context) (bool, error) { - row := s.dbpool.QueryRow(ctx, "SELECT 1") - var col int - err := row.Scan(&col) - if err == nil { - return true, nil - } else { - return false, fmt.Errorf("database health check failed: %v", err) - } -} - -// Check if JobSet is in our map. -func (s *JSRepoPostgres) IsJobSetSubscribed(ctx context.Context, queue string, jobSet string) (bool, string, error) { - sqlStmt := "SELECT Queue, Id, FromMessageId FROM jobsets WHERE Queue = $1 AND Id = $2" - row := s.dbpool.QueryRow(ctx, sqlStmt, queue, jobSet) - var queueScan, jobSetIdScan, fromMessageId string - - err := row.Scan(&queueScan, &jobSetIdScan, &fromMessageId) - - if err == pgx.ErrNoRows { - return false, "", nil - } else if err != nil { - return false, "", err - } - return true, fromMessageId, nil -} - -// Clear subscription error if present -func (s *JSRepoPostgres) AddMessageIdAndClearSubscriptionError(ctx context.Context, queue string, - jobSet string, fromMessageId string, -) error { - return s.SetSubscriptionError(ctx, queue, jobSet, "", fromMessageId) -} - -// Set subscription error if present -func (s *JSRepoPostgres) SetSubscriptionError(ctx context.Context, queue string, jobSet string, - connErr string, fromMessageId string, -) error { - sqlStmt := `INSERT INTO jobsets (Queue, Id, Timestamp, ConnectionError, FromMessageId) - VALUES ($1, $2, $3, $4, $5) ON CONFLICT (Queue, Id) DO UPDATE SET - (Timestamp, ConnectionError, FromMessageId) = - (excluded.Timestamp, excluded.ConnectionError, excluded.FromMessageId)` - - subscribeTable := NewSubscribeTable(queue, jobSet) - _, jobSetErr := s.dbpool.Exec(ctx, sqlStmt, subscribeTable.queue, jobSet, subscribeTable.lastRequestTimeStamp, - connErr, fromMessageId) - if jobSetErr != nil { - return jobSetErr - } - return jobSetErr -} - -// Get subscription error if present -func (s *JSRepoPostgres) GetSubscriptionError(ctx context.Context, queue string, jobSet string) (string, error) { - sqlStmt := "SELECT ConnectionError FROM jobsets WHERE Queue = $1 AND Id = $2" - row := s.dbpool.QueryRow(ctx, sqlStmt, queue, jobSet) - var connError string - - err := row.Scan(&connError) - - if err == pgx.ErrNoRows { - return "", nil - } else if err != nil { - return "", err - } - return connError, nil -} - -// Mark our JobSet as being subscribed -// SubscribeTable contains Queue, JobSet and time when it was created. -func (s *JSRepoPostgres) SubscribeJobSet(ctx context.Context, queue string, jobSet string, - fromMessageId string, -) error { - sqlStmt := `INSERT INTO jobsets (Queue, Id, Timestamp, ConnectionError, FromMessageId) - VALUES ($1, $2, $3, $4, $5) ON CONFLICT (Queue, Id) DO UPDATE SET - (Timestamp, ConnectionError, FromMessageId) = - (excluded.Timestamp, excluded.ConnectionError, excluded.FromMessageId)` - - subscribeTable := NewSubscribeTable(queue, jobSet) - _, jobSetErr := s.dbpool.Exec(ctx, sqlStmt, subscribeTable.queue, subscribeTable.jobSet, - subscribeTable.lastRequestTimeStamp, "", fromMessageId) - return jobSetErr -} - -// Checks JobSet table to make determine if we should unsubscribe from JobSet -// configTimeWithoutUpdates is a configurable value that is read from the config -// We allow unsubscribing if the jobset hasn't been updated in configTime -// TODO implement this -func (s *JSRepoPostgres) CheckToUnSubscribe(ctx context.Context, queue string, jobSet string, - configTimeWithoutUpdates time.Duration, -) (bool, error) { - jobSetFound, _, err := s.IsJobSetSubscribed(ctx, queue, jobSet) - if err != nil { - return false, nil - } - if !jobSetFound { - return false, nil - } - - sqlStmt := "SELECT Timestamp FROM jobsets WHERE Queue = $1 AND Id = $2" - - row := s.dbpool.QueryRow(ctx, sqlStmt, queue, jobSet) - var timeStamp int64 - - timeErr := row.Scan(&timeStamp) - - if timeErr == pgx.ErrNoRows { - return false, nil - } else if err != nil { - return false, err - } - - currentTime := time.Now() - lastUpdate := time.Unix(timeStamp, 0) - if currentTime.After(lastUpdate.Add(configTimeWithoutUpdates)) { - return true, nil - } - return false, nil -} - -// Deletes the corresponding jobset along with it's associated jobs due to -// the CASCADE DELETE constraint on the foreign-key relationship. -func (s *JSRepoPostgres) UnsubscribeJobSet(ctx context.Context, queue, jobSet string) (int64, error) { - sqlStmt := "DELETE FROM jobsets WHERE Queue = $1 AND Id = $2" - - result, err := s.dbpool.Exec(ctx, sqlStmt, queue, jobSet) - if err != nil { - return 0, err - } - return result.RowsAffected(), nil -} - -// Delete Jobs in the database -func (s *JSRepoPostgres) DeleteJobsInJobSet(ctx context.Context, queue string, jobSet string) (int64, error) { - sqlStmt := "DELETE FROM jobs WHERE Queue = $1 AND JobSetId = $2" - - result, err := s.dbpool.Exec(ctx, sqlStmt, queue, jobSet) - if err != nil { - return 0, err - } - return result.RowsAffected(), nil -} - -func (s *JSRepoPostgres) GetSubscribedJobSets(ctx context.Context) ([]SubscribedTuple, error) { - rows, err := s.dbpool.Query(ctx, "SELECT Queue, Id, FromMessageId FROM jobsets") - if err != nil { - return nil, err - } - defer rows.Close() - - var tuples []SubscribedTuple - - // Loop through rows, using Scan to assign column data to struct fields. - for rows.Next() { - var st SubscribedTuple - if err := rows.Scan(&st.Queue, &st.JobSetId, &st.FromMessageId); err != nil { - return tuples, err - } - tuples = append(tuples, st) - } - if err = rows.Err(); err != nil { - return tuples, err - } - return tuples, nil -} - -// PurgeExpiredJobSets purges all expired Jobs/JobSets from the database -// An expired Job/JobSet is a Job/JobSet that has not been updated within the specified PurgeJobSetTime period. -func (s *JSRepoPostgres) PurgeExpiredJobSets(ctx context.Context) { - jobSetStmt := fmt.Sprintf(`DELETE FROM jobsets WHERE Timestamp < (extract(epoch from now()) - %d);`, s.jobServiceConfig.PurgeJobSetTime) - jobStmt := fmt.Sprintf(`DELETE FROM jobs WHERE Timestamp < (extract(epoch from now()) - %d);`, s.jobServiceConfig.PurgeJobSetTime) - ticker := time.NewTicker(time.Duration(s.jobServiceConfig.PurgeJobSetTime) * time.Second) - log := log.WithField("JobService", "ExpiredJobSetsPurge") - - log.Info("Starting purge of expired jobsets") - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - result, err := s.dbpool.Exec(ctx, jobSetStmt) - if err != nil { - log.Error("error deleting expired jobsets: ", err) - } else { - log.Debugf("Deleted %d expired jobsets", result.RowsAffected()) - } - result, err = s.dbpool.Exec(ctx, jobStmt) - if err != nil { - log.Error("error deleting expired jobs: ", err) - } else { - log.Debugf("Deleted %d expired jobs", result.RowsAffected()) - } - } - } -} diff --git a/internal/jobservice/repository/sql_job_service.go b/internal/jobservice/repository/sql_job_service.go deleted file mode 100644 index e24b6e66843..00000000000 --- a/internal/jobservice/repository/sql_job_service.go +++ /dev/null @@ -1,90 +0,0 @@ -package repository - -import ( - "context" - "errors" - "fmt" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/armadaproject/armada/internal/jobservice/configuration" - js "github.com/armadaproject/armada/pkg/api/jobservice" -) - -//go:generate moq -out job_table_updater_moq.go . JobTableUpdater -type JobTableUpdater interface { - SubscribeJobSet(ctx context.Context, queue string, jobSet string, fromMessageId string) error - IsJobSetSubscribed(ctx context.Context, queue string, jobSet string) (bool, string, error) - UpdateJobServiceDb(ctx context.Context, jobTable *JobStatus) error - UpdateJobSetDb(ctx context.Context, queue string, jobSet string, fromMessageId string) error - SetSubscriptionError(ctx context.Context, queue string, jobSet string, err string, fromMessageId string) error - GetSubscriptionError(ctx context.Context, queue string, jobSet string) (string, error) - AddMessageIdAndClearSubscriptionError(ctx context.Context, queue string, jobSet string, messageId string) error - UnsubscribeJobSet(ctx context.Context, queue string, jobSet string) (int64, error) - GetSubscribedJobSets(ctx context.Context) ([]SubscribedTuple, error) -} - -// SQLJobService for persisting to DB. -// -//go:generate moq -out sql_job_service_moq.go . SQLJobService -type SQLJobService interface { - AddMessageIdAndClearSubscriptionError(ctx context.Context, queue string, jobSet string, fromMessageId string) error - CheckToUnSubscribe(ctx context.Context, queue string, jobSet string, configTimeWithoutUpdates time.Duration) (bool, error) - DeleteJobsInJobSet(ctx context.Context, queue string, jobSet string) (int64, error) - GetJobStatus(ctx context.Context, jobId string) (*js.JobServiceResponse, error) - GetSubscribedJobSets(ctx context.Context) ([]SubscribedTuple, error) - GetSubscriptionError(ctx context.Context, queue string, jobSet string) (string, error) - HealthCheck(ctx context.Context) (bool, error) - IsJobSetSubscribed(ctx context.Context, queue string, jobSet string) (bool, string, error) - SetSubscriptionError(ctx context.Context, queue string, jobSet string, connErr string, fromMessageId string) error - Setup(ctx context.Context) - SubscribeJobSet(ctx context.Context, queue string, jobSet string, fromMessageId string) error - UnsubscribeJobSet(ctx context.Context, queue, jobSet string) (int64, error) - UpdateJobServiceDb(ctx context.Context, jobTable *JobStatus) error - UpdateJobSetDb(ctx context.Context, queue string, jobSet string, fromMessageId string) error - PurgeExpiredJobSets(ctx context.Context) -} - -func NewSQLJobService(cfg *configuration.JobServiceConfiguration, log *log.Entry) (error, SQLJobService, func()) { - if cfg.DatabaseType == "postgres" { - return NewJSRepoPostgres(cfg, log) - } else if cfg.DatabaseType == "sqlite" { - return NewJSRepoSQLite(cfg, log) - } - - return errors.New("database type must be either 'postgres' or 'sqlite'"), nil, func() {} -} - -type JobSetKey struct { - Queue string - JobSetId string -} - -type SubscribedTuple struct { - JobSetKey - - FromMessageId string -} - -func JobStateStrToJSRState(jobState string) (js.JobServiceResponse_State, error) { - switch jobState { - case "SUBMITTED": - return js.JobServiceResponse_SUBMITTED, nil - case "DUPLICATE_FOUND": - return js.JobServiceResponse_DUPLICATE_FOUND, nil - case "RUNNING": - return js.JobServiceResponse_RUNNING, nil - case "FAILED": - return js.JobServiceResponse_FAILED, nil - case "SUCCEEDED": - return js.JobServiceResponse_SUCCEEDED, nil - case "CANCELLED": - return js.JobServiceResponse_CANCELLED, nil - case "JOB_ID_NOT_FOUND": - return js.JobServiceResponse_JOB_ID_NOT_FOUND, nil - } - - return js.JobServiceResponse_JOB_ID_NOT_FOUND, - fmt.Errorf("JobStateStrToJSRState: invalid job state string '%s'", jobState) -} diff --git a/internal/jobservice/repository/sql_job_service_moq.go b/internal/jobservice/repository/sql_job_service_moq.go deleted file mode 100644 index 6c637c22040..00000000000 --- a/internal/jobservice/repository/sql_job_service_moq.go +++ /dev/null @@ -1,850 +0,0 @@ -// Code generated by moq; DO NOT EDIT. -// github.com/matryer/moq - -package repository - -import ( - "context" - "sync" - "time" - - js "github.com/armadaproject/armada/pkg/api/jobservice" -) - -// Ensure, that SQLJobServiceMock does implement SQLJobService. -// If this is not the case, regenerate this file with moq. -var _ SQLJobService = &SQLJobServiceMock{} - -// SQLJobServiceMock is a mock implementation of SQLJobService. -// -// func TestSomethingThatUsesSQLJobService(t *testing.T) { -// -// // make and configure a mocked SQLJobService -// mockedSQLJobService := &SQLJobServiceMock{ -// AddMessageIdAndClearSubscriptionErrorFunc: func(ctx context.Context, queue string, jobSet string, fromMessageId string) error { -// panic("mock out the AddMessageIdAndClearSubscriptionError method") -// }, -// CheckToUnSubscribeFunc: func(ctx context.Context, queue string, jobSet string, configTimeWithoutUpdates time.Duration) (bool, error) { -// panic("mock out the CheckToUnSubscribe method") -// }, -// DeleteJobsInJobSetFunc: func(ctx context.Context, queue string, jobSet string) (int64, error) { -// panic("mock out the DeleteJobsInJobSet method") -// }, -// GetJobStatusFunc: func(ctx context.Context, jobId string) (*js.JobServiceResponse, error) { -// panic("mock out the GetJobStatus method") -// }, -// GetSubscribedJobSetsFunc: func(ctx context.Context) ([]SubscribedTuple, error) { -// panic("mock out the GetSubscribedJobSets method") -// }, -// GetSubscriptionErrorFunc: func(ctx context.Context, queue string, jobSet string) (string, error) { -// panic("mock out the GetSubscriptionError method") -// }, -// HealthCheckFunc: func(ctx context.Context) (bool, error) { -// panic("mock out the HealthCheck method") -// }, -// IsJobSetSubscribedFunc: func(ctx context.Context, queue string, jobSet string) (bool, string, error) { -// panic("mock out the IsJobSetSubscribed method") -// }, -// PurgeExpiredJobSetsFunc: func(ctx context.Context) { -// panic("mock out the PurgeExpiredJobSets method") -// }, -// SetSubscriptionErrorFunc: func(ctx context.Context, queue string, jobSet string, connErr string, fromMessageId string) error { -// panic("mock out the SetSubscriptionError method") -// }, -// SetupFunc: func(ctx context.Context) { -// panic("mock out the Setup method") -// }, -// SubscribeJobSetFunc: func(ctx context.Context, queue string, jobSet string, fromMessageId string) error { -// panic("mock out the SubscribeJobSet method") -// }, -// UnsubscribeJobSetFunc: func(ctx context.Context, queue string, jobSet string) (int64, error) { -// panic("mock out the UnsubscribeJobSet method") -// }, -// UpdateJobServiceDbFunc: func(ctx context.Context, jobTable *JobStatus) error { -// panic("mock out the UpdateJobServiceDb method") -// }, -// UpdateJobSetDbFunc: func(ctx context.Context, queue string, jobSet string, fromMessageId string) error { -// panic("mock out the UpdateJobSetDb method") -// }, -// } -// -// // use mockedSQLJobService in code that requires SQLJobService -// // and then make assertions. -// -// } -type SQLJobServiceMock struct { - // AddMessageIdAndClearSubscriptionErrorFunc mocks the AddMessageIdAndClearSubscriptionError method. - AddMessageIdAndClearSubscriptionErrorFunc func(ctx context.Context, queue string, jobSet string, fromMessageId string) error - - // CheckToUnSubscribeFunc mocks the CheckToUnSubscribe method. - CheckToUnSubscribeFunc func(ctx context.Context, queue string, jobSet string, configTimeWithoutUpdates time.Duration) (bool, error) - - // DeleteJobsInJobSetFunc mocks the DeleteJobsInJobSet method. - DeleteJobsInJobSetFunc func(ctx context.Context, queue string, jobSet string) (int64, error) - - // GetJobStatusFunc mocks the GetJobStatus method. - GetJobStatusFunc func(ctx context.Context, jobId string) (*js.JobServiceResponse, error) - - // GetSubscribedJobSetsFunc mocks the GetSubscribedJobSets method. - GetSubscribedJobSetsFunc func(ctx context.Context) ([]SubscribedTuple, error) - - // GetSubscriptionErrorFunc mocks the GetSubscriptionError method. - GetSubscriptionErrorFunc func(ctx context.Context, queue string, jobSet string) (string, error) - - // HealthCheckFunc mocks the HealthCheck method. - HealthCheckFunc func(ctx context.Context) (bool, error) - - // IsJobSetSubscribedFunc mocks the IsJobSetSubscribed method. - IsJobSetSubscribedFunc func(ctx context.Context, queue string, jobSet string) (bool, string, error) - - // PurgeExpiredJobSetsFunc mocks the PurgeExpiredJobSets method. - PurgeExpiredJobSetsFunc func(ctx context.Context) - - // SetSubscriptionErrorFunc mocks the SetSubscriptionError method. - SetSubscriptionErrorFunc func(ctx context.Context, queue string, jobSet string, connErr string, fromMessageId string) error - - // SetupFunc mocks the Setup method. - SetupFunc func(ctx context.Context) - - // SubscribeJobSetFunc mocks the SubscribeJobSet method. - SubscribeJobSetFunc func(ctx context.Context, queue string, jobSet string, fromMessageId string) error - - // UnsubscribeJobSetFunc mocks the UnsubscribeJobSet method. - UnsubscribeJobSetFunc func(ctx context.Context, queue string, jobSet string) (int64, error) - - // UpdateJobServiceDbFunc mocks the UpdateJobServiceDb method. - UpdateJobServiceDbFunc func(ctx context.Context, jobTable *JobStatus) error - - // UpdateJobSetDbFunc mocks the UpdateJobSetDb method. - UpdateJobSetDbFunc func(ctx context.Context, queue string, jobSet string, fromMessageId string) error - - // calls tracks calls to the methods. - calls struct { - // AddMessageIdAndClearSubscriptionError holds details about calls to the AddMessageIdAndClearSubscriptionError method. - AddMessageIdAndClearSubscriptionError []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // FromMessageId is the fromMessageId argument value. - FromMessageId string - } - // CheckToUnSubscribe holds details about calls to the CheckToUnSubscribe method. - CheckToUnSubscribe []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // ConfigTimeWithoutUpdates is the configTimeWithoutUpdates argument value. - ConfigTimeWithoutUpdates time.Duration - } - // DeleteJobsInJobSet holds details about calls to the DeleteJobsInJobSet method. - DeleteJobsInJobSet []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - } - // GetJobStatus holds details about calls to the GetJobStatus method. - GetJobStatus []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // JobId is the jobId argument value. - JobId string - } - // GetSubscribedJobSets holds details about calls to the GetSubscribedJobSets method. - GetSubscribedJobSets []struct { - // Ctx is the ctx argument value. - Ctx context.Context - } - // GetSubscriptionError holds details about calls to the GetSubscriptionError method. - GetSubscriptionError []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - } - // HealthCheck holds details about calls to the HealthCheck method. - HealthCheck []struct { - // Ctx is the ctx argument value. - Ctx context.Context - } - // IsJobSetSubscribed holds details about calls to the IsJobSetSubscribed method. - IsJobSetSubscribed []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - } - // PurgeExpiredJobSets holds details about calls to the PurgeExpiredJobSets method. - PurgeExpiredJobSets []struct { - // Ctx is the ctx argument value. - Ctx context.Context - } - // SetSubscriptionError holds details about calls to the SetSubscriptionError method. - SetSubscriptionError []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // ConnErr is the connErr argument value. - ConnErr string - // FromMessageId is the fromMessageId argument value. - FromMessageId string - } - // Setup holds details about calls to the Setup method. - Setup []struct { - // Ctx is the ctx argument value. - Ctx context.Context - } - // SubscribeJobSet holds details about calls to the SubscribeJobSet method. - SubscribeJobSet []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // FromMessageId is the fromMessageId argument value. - FromMessageId string - } - // UnsubscribeJobSet holds details about calls to the UnsubscribeJobSet method. - UnsubscribeJobSet []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - } - // UpdateJobServiceDb holds details about calls to the UpdateJobServiceDb method. - UpdateJobServiceDb []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // JobTable is the jobTable argument value. - JobTable *JobStatus - } - // UpdateJobSetDb holds details about calls to the UpdateJobSetDb method. - UpdateJobSetDb []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Queue is the queue argument value. - Queue string - // JobSet is the jobSet argument value. - JobSet string - // FromMessageId is the fromMessageId argument value. - FromMessageId string - } - } - lockAddMessageIdAndClearSubscriptionError sync.RWMutex - lockCheckToUnSubscribe sync.RWMutex - lockDeleteJobsInJobSet sync.RWMutex - lockGetJobStatus sync.RWMutex - lockGetSubscribedJobSets sync.RWMutex - lockGetSubscriptionError sync.RWMutex - lockHealthCheck sync.RWMutex - lockIsJobSetSubscribed sync.RWMutex - lockPurgeExpiredJobSets sync.RWMutex - lockSetSubscriptionError sync.RWMutex - lockSetup sync.RWMutex - lockSubscribeJobSet sync.RWMutex - lockUnsubscribeJobSet sync.RWMutex - lockUpdateJobServiceDb sync.RWMutex - lockUpdateJobSetDb sync.RWMutex -} - -// AddMessageIdAndClearSubscriptionError calls AddMessageIdAndClearSubscriptionErrorFunc. -func (mock *SQLJobServiceMock) AddMessageIdAndClearSubscriptionError(ctx context.Context, queue string, jobSet string, fromMessageId string) error { - if mock.AddMessageIdAndClearSubscriptionErrorFunc == nil { - panic("SQLJobServiceMock.AddMessageIdAndClearSubscriptionErrorFunc: method is nil but SQLJobService.AddMessageIdAndClearSubscriptionError was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - FromMessageId: fromMessageId, - } - mock.lockAddMessageIdAndClearSubscriptionError.Lock() - mock.calls.AddMessageIdAndClearSubscriptionError = append(mock.calls.AddMessageIdAndClearSubscriptionError, callInfo) - mock.lockAddMessageIdAndClearSubscriptionError.Unlock() - return mock.AddMessageIdAndClearSubscriptionErrorFunc(ctx, queue, jobSet, fromMessageId) -} - -// AddMessageIdAndClearSubscriptionErrorCalls gets all the calls that were made to AddMessageIdAndClearSubscriptionError. -// Check the length with: -// -// len(mockedSQLJobService.AddMessageIdAndClearSubscriptionErrorCalls()) -func (mock *SQLJobServiceMock) AddMessageIdAndClearSubscriptionErrorCalls() []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - } - mock.lockAddMessageIdAndClearSubscriptionError.RLock() - calls = mock.calls.AddMessageIdAndClearSubscriptionError - mock.lockAddMessageIdAndClearSubscriptionError.RUnlock() - return calls -} - -// CheckToUnSubscribe calls CheckToUnSubscribeFunc. -func (mock *SQLJobServiceMock) CheckToUnSubscribe(ctx context.Context, queue string, jobSet string, configTimeWithoutUpdates time.Duration) (bool, error) { - if mock.CheckToUnSubscribeFunc == nil { - panic("SQLJobServiceMock.CheckToUnSubscribeFunc: method is nil but SQLJobService.CheckToUnSubscribe was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - ConfigTimeWithoutUpdates time.Duration - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - ConfigTimeWithoutUpdates: configTimeWithoutUpdates, - } - mock.lockCheckToUnSubscribe.Lock() - mock.calls.CheckToUnSubscribe = append(mock.calls.CheckToUnSubscribe, callInfo) - mock.lockCheckToUnSubscribe.Unlock() - return mock.CheckToUnSubscribeFunc(ctx, queue, jobSet, configTimeWithoutUpdates) -} - -// CheckToUnSubscribeCalls gets all the calls that were made to CheckToUnSubscribe. -// Check the length with: -// -// len(mockedSQLJobService.CheckToUnSubscribeCalls()) -func (mock *SQLJobServiceMock) CheckToUnSubscribeCalls() []struct { - Ctx context.Context - Queue string - JobSet string - ConfigTimeWithoutUpdates time.Duration -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - ConfigTimeWithoutUpdates time.Duration - } - mock.lockCheckToUnSubscribe.RLock() - calls = mock.calls.CheckToUnSubscribe - mock.lockCheckToUnSubscribe.RUnlock() - return calls -} - -// DeleteJobsInJobSet calls DeleteJobsInJobSetFunc. -func (mock *SQLJobServiceMock) DeleteJobsInJobSet(ctx context.Context, queue string, jobSet string) (int64, error) { - if mock.DeleteJobsInJobSetFunc == nil { - panic("SQLJobServiceMock.DeleteJobsInJobSetFunc: method is nil but SQLJobService.DeleteJobsInJobSet was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - } - mock.lockDeleteJobsInJobSet.Lock() - mock.calls.DeleteJobsInJobSet = append(mock.calls.DeleteJobsInJobSet, callInfo) - mock.lockDeleteJobsInJobSet.Unlock() - return mock.DeleteJobsInJobSetFunc(ctx, queue, jobSet) -} - -// DeleteJobsInJobSetCalls gets all the calls that were made to DeleteJobsInJobSet. -// Check the length with: -// -// len(mockedSQLJobService.DeleteJobsInJobSetCalls()) -func (mock *SQLJobServiceMock) DeleteJobsInJobSetCalls() []struct { - Ctx context.Context - Queue string - JobSet string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - } - mock.lockDeleteJobsInJobSet.RLock() - calls = mock.calls.DeleteJobsInJobSet - mock.lockDeleteJobsInJobSet.RUnlock() - return calls -} - -// GetJobStatus calls GetJobStatusFunc. -func (mock *SQLJobServiceMock) GetJobStatus(ctx context.Context, jobId string) (*js.JobServiceResponse, error) { - if mock.GetJobStatusFunc == nil { - panic("SQLJobServiceMock.GetJobStatusFunc: method is nil but SQLJobService.GetJobStatus was just called") - } - callInfo := struct { - Ctx context.Context - JobId string - }{ - Ctx: ctx, - JobId: jobId, - } - mock.lockGetJobStatus.Lock() - mock.calls.GetJobStatus = append(mock.calls.GetJobStatus, callInfo) - mock.lockGetJobStatus.Unlock() - return mock.GetJobStatusFunc(ctx, jobId) -} - -// GetJobStatusCalls gets all the calls that were made to GetJobStatus. -// Check the length with: -// -// len(mockedSQLJobService.GetJobStatusCalls()) -func (mock *SQLJobServiceMock) GetJobStatusCalls() []struct { - Ctx context.Context - JobId string -} { - var calls []struct { - Ctx context.Context - JobId string - } - mock.lockGetJobStatus.RLock() - calls = mock.calls.GetJobStatus - mock.lockGetJobStatus.RUnlock() - return calls -} - -// GetSubscribedJobSets calls GetSubscribedJobSetsFunc. -func (mock *SQLJobServiceMock) GetSubscribedJobSets(ctx context.Context) ([]SubscribedTuple, error) { - if mock.GetSubscribedJobSetsFunc == nil { - panic("SQLJobServiceMock.GetSubscribedJobSetsFunc: method is nil but SQLJobService.GetSubscribedJobSets was just called") - } - callInfo := struct { - Ctx context.Context - }{ - Ctx: ctx, - } - mock.lockGetSubscribedJobSets.Lock() - mock.calls.GetSubscribedJobSets = append(mock.calls.GetSubscribedJobSets, callInfo) - mock.lockGetSubscribedJobSets.Unlock() - return mock.GetSubscribedJobSetsFunc(ctx) -} - -// GetSubscribedJobSetsCalls gets all the calls that were made to GetSubscribedJobSets. -// Check the length with: -// -// len(mockedSQLJobService.GetSubscribedJobSetsCalls()) -func (mock *SQLJobServiceMock) GetSubscribedJobSetsCalls() []struct { - Ctx context.Context -} { - var calls []struct { - Ctx context.Context - } - mock.lockGetSubscribedJobSets.RLock() - calls = mock.calls.GetSubscribedJobSets - mock.lockGetSubscribedJobSets.RUnlock() - return calls -} - -// GetSubscriptionError calls GetSubscriptionErrorFunc. -func (mock *SQLJobServiceMock) GetSubscriptionError(ctx context.Context, queue string, jobSet string) (string, error) { - if mock.GetSubscriptionErrorFunc == nil { - panic("SQLJobServiceMock.GetSubscriptionErrorFunc: method is nil but SQLJobService.GetSubscriptionError was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - } - mock.lockGetSubscriptionError.Lock() - mock.calls.GetSubscriptionError = append(mock.calls.GetSubscriptionError, callInfo) - mock.lockGetSubscriptionError.Unlock() - return mock.GetSubscriptionErrorFunc(ctx, queue, jobSet) -} - -// GetSubscriptionErrorCalls gets all the calls that were made to GetSubscriptionError. -// Check the length with: -// -// len(mockedSQLJobService.GetSubscriptionErrorCalls()) -func (mock *SQLJobServiceMock) GetSubscriptionErrorCalls() []struct { - Ctx context.Context - Queue string - JobSet string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - } - mock.lockGetSubscriptionError.RLock() - calls = mock.calls.GetSubscriptionError - mock.lockGetSubscriptionError.RUnlock() - return calls -} - -// HealthCheck calls HealthCheckFunc. -func (mock *SQLJobServiceMock) HealthCheck(ctx context.Context) (bool, error) { - if mock.HealthCheckFunc == nil { - panic("SQLJobServiceMock.HealthCheckFunc: method is nil but SQLJobService.HealthCheck was just called") - } - callInfo := struct { - Ctx context.Context - }{ - Ctx: ctx, - } - mock.lockHealthCheck.Lock() - mock.calls.HealthCheck = append(mock.calls.HealthCheck, callInfo) - mock.lockHealthCheck.Unlock() - return mock.HealthCheckFunc(ctx) -} - -// HealthCheckCalls gets all the calls that were made to HealthCheck. -// Check the length with: -// -// len(mockedSQLJobService.HealthCheckCalls()) -func (mock *SQLJobServiceMock) HealthCheckCalls() []struct { - Ctx context.Context -} { - var calls []struct { - Ctx context.Context - } - mock.lockHealthCheck.RLock() - calls = mock.calls.HealthCheck - mock.lockHealthCheck.RUnlock() - return calls -} - -// IsJobSetSubscribed calls IsJobSetSubscribedFunc. -func (mock *SQLJobServiceMock) IsJobSetSubscribed(ctx context.Context, queue string, jobSet string) (bool, string, error) { - if mock.IsJobSetSubscribedFunc == nil { - panic("SQLJobServiceMock.IsJobSetSubscribedFunc: method is nil but SQLJobService.IsJobSetSubscribed was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - } - mock.lockIsJobSetSubscribed.Lock() - mock.calls.IsJobSetSubscribed = append(mock.calls.IsJobSetSubscribed, callInfo) - mock.lockIsJobSetSubscribed.Unlock() - return mock.IsJobSetSubscribedFunc(ctx, queue, jobSet) -} - -// IsJobSetSubscribedCalls gets all the calls that were made to IsJobSetSubscribed. -// Check the length with: -// -// len(mockedSQLJobService.IsJobSetSubscribedCalls()) -func (mock *SQLJobServiceMock) IsJobSetSubscribedCalls() []struct { - Ctx context.Context - Queue string - JobSet string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - } - mock.lockIsJobSetSubscribed.RLock() - calls = mock.calls.IsJobSetSubscribed - mock.lockIsJobSetSubscribed.RUnlock() - return calls -} - -// PurgeExpiredJobSets calls PurgeExpiredJobSetsFunc. -func (mock *SQLJobServiceMock) PurgeExpiredJobSets(ctx context.Context) { - if mock.PurgeExpiredJobSetsFunc == nil { - panic("SQLJobServiceMock.PurgeExpiredJobSetsFunc: method is nil but SQLJobService.PurgeExpiredJobSets was just called") - } - callInfo := struct { - Ctx context.Context - }{ - Ctx: ctx, - } - mock.lockPurgeExpiredJobSets.Lock() - mock.calls.PurgeExpiredJobSets = append(mock.calls.PurgeExpiredJobSets, callInfo) - mock.lockPurgeExpiredJobSets.Unlock() - mock.PurgeExpiredJobSetsFunc(ctx) -} - -// PurgeExpiredJobSetsCalls gets all the calls that were made to PurgeExpiredJobSets. -// Check the length with: -// -// len(mockedSQLJobService.PurgeExpiredJobSetsCalls()) -func (mock *SQLJobServiceMock) PurgeExpiredJobSetsCalls() []struct { - Ctx context.Context -} { - var calls []struct { - Ctx context.Context - } - mock.lockPurgeExpiredJobSets.RLock() - calls = mock.calls.PurgeExpiredJobSets - mock.lockPurgeExpiredJobSets.RUnlock() - return calls -} - -// SetSubscriptionError calls SetSubscriptionErrorFunc. -func (mock *SQLJobServiceMock) SetSubscriptionError(ctx context.Context, queue string, jobSet string, connErr string, fromMessageId string) error { - if mock.SetSubscriptionErrorFunc == nil { - panic("SQLJobServiceMock.SetSubscriptionErrorFunc: method is nil but SQLJobService.SetSubscriptionError was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - ConnErr string - FromMessageId string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - ConnErr: connErr, - FromMessageId: fromMessageId, - } - mock.lockSetSubscriptionError.Lock() - mock.calls.SetSubscriptionError = append(mock.calls.SetSubscriptionError, callInfo) - mock.lockSetSubscriptionError.Unlock() - return mock.SetSubscriptionErrorFunc(ctx, queue, jobSet, connErr, fromMessageId) -} - -// SetSubscriptionErrorCalls gets all the calls that were made to SetSubscriptionError. -// Check the length with: -// -// len(mockedSQLJobService.SetSubscriptionErrorCalls()) -func (mock *SQLJobServiceMock) SetSubscriptionErrorCalls() []struct { - Ctx context.Context - Queue string - JobSet string - ConnErr string - FromMessageId string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - ConnErr string - FromMessageId string - } - mock.lockSetSubscriptionError.RLock() - calls = mock.calls.SetSubscriptionError - mock.lockSetSubscriptionError.RUnlock() - return calls -} - -// Setup calls SetupFunc. -func (mock *SQLJobServiceMock) Setup(ctx context.Context) { - if mock.SetupFunc == nil { - panic("SQLJobServiceMock.SetupFunc: method is nil but SQLJobService.Setup was just called") - } - callInfo := struct { - Ctx context.Context - }{ - Ctx: ctx, - } - mock.lockSetup.Lock() - mock.calls.Setup = append(mock.calls.Setup, callInfo) - mock.lockSetup.Unlock() - mock.SetupFunc(ctx) -} - -// SetupCalls gets all the calls that were made to Setup. -// Check the length with: -// -// len(mockedSQLJobService.SetupCalls()) -func (mock *SQLJobServiceMock) SetupCalls() []struct { - Ctx context.Context -} { - var calls []struct { - Ctx context.Context - } - mock.lockSetup.RLock() - calls = mock.calls.Setup - mock.lockSetup.RUnlock() - return calls -} - -// SubscribeJobSet calls SubscribeJobSetFunc. -func (mock *SQLJobServiceMock) SubscribeJobSet(ctx context.Context, queue string, jobSet string, fromMessageId string) error { - if mock.SubscribeJobSetFunc == nil { - panic("SQLJobServiceMock.SubscribeJobSetFunc: method is nil but SQLJobService.SubscribeJobSet was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - FromMessageId: fromMessageId, - } - mock.lockSubscribeJobSet.Lock() - mock.calls.SubscribeJobSet = append(mock.calls.SubscribeJobSet, callInfo) - mock.lockSubscribeJobSet.Unlock() - return mock.SubscribeJobSetFunc(ctx, queue, jobSet, fromMessageId) -} - -// SubscribeJobSetCalls gets all the calls that were made to SubscribeJobSet. -// Check the length with: -// -// len(mockedSQLJobService.SubscribeJobSetCalls()) -func (mock *SQLJobServiceMock) SubscribeJobSetCalls() []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - } - mock.lockSubscribeJobSet.RLock() - calls = mock.calls.SubscribeJobSet - mock.lockSubscribeJobSet.RUnlock() - return calls -} - -// UnsubscribeJobSet calls UnsubscribeJobSetFunc. -func (mock *SQLJobServiceMock) UnsubscribeJobSet(ctx context.Context, queue string, jobSet string) (int64, error) { - if mock.UnsubscribeJobSetFunc == nil { - panic("SQLJobServiceMock.UnsubscribeJobSetFunc: method is nil but SQLJobService.UnsubscribeJobSet was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - } - mock.lockUnsubscribeJobSet.Lock() - mock.calls.UnsubscribeJobSet = append(mock.calls.UnsubscribeJobSet, callInfo) - mock.lockUnsubscribeJobSet.Unlock() - return mock.UnsubscribeJobSetFunc(ctx, queue, jobSet) -} - -// UnsubscribeJobSetCalls gets all the calls that were made to UnsubscribeJobSet. -// Check the length with: -// -// len(mockedSQLJobService.UnsubscribeJobSetCalls()) -func (mock *SQLJobServiceMock) UnsubscribeJobSetCalls() []struct { - Ctx context.Context - Queue string - JobSet string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - } - mock.lockUnsubscribeJobSet.RLock() - calls = mock.calls.UnsubscribeJobSet - mock.lockUnsubscribeJobSet.RUnlock() - return calls -} - -// UpdateJobServiceDb calls UpdateJobServiceDbFunc. -func (mock *SQLJobServiceMock) UpdateJobServiceDb(ctx context.Context, jobTable *JobStatus) error { - if mock.UpdateJobServiceDbFunc == nil { - panic("SQLJobServiceMock.UpdateJobServiceDbFunc: method is nil but SQLJobService.UpdateJobServiceDb was just called") - } - callInfo := struct { - Ctx context.Context - JobTable *JobStatus - }{ - Ctx: ctx, - JobTable: jobTable, - } - mock.lockUpdateJobServiceDb.Lock() - mock.calls.UpdateJobServiceDb = append(mock.calls.UpdateJobServiceDb, callInfo) - mock.lockUpdateJobServiceDb.Unlock() - return mock.UpdateJobServiceDbFunc(ctx, jobTable) -} - -// UpdateJobServiceDbCalls gets all the calls that were made to UpdateJobServiceDb. -// Check the length with: -// -// len(mockedSQLJobService.UpdateJobServiceDbCalls()) -func (mock *SQLJobServiceMock) UpdateJobServiceDbCalls() []struct { - Ctx context.Context - JobTable *JobStatus -} { - var calls []struct { - Ctx context.Context - JobTable *JobStatus - } - mock.lockUpdateJobServiceDb.RLock() - calls = mock.calls.UpdateJobServiceDb - mock.lockUpdateJobServiceDb.RUnlock() - return calls -} - -// UpdateJobSetDb calls UpdateJobSetDbFunc. -func (mock *SQLJobServiceMock) UpdateJobSetDb(ctx context.Context, queue string, jobSet string, fromMessageId string) error { - if mock.UpdateJobSetDbFunc == nil { - panic("SQLJobServiceMock.UpdateJobSetDbFunc: method is nil but SQLJobService.UpdateJobSetDb was just called") - } - callInfo := struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - }{ - Ctx: ctx, - Queue: queue, - JobSet: jobSet, - FromMessageId: fromMessageId, - } - mock.lockUpdateJobSetDb.Lock() - mock.calls.UpdateJobSetDb = append(mock.calls.UpdateJobSetDb, callInfo) - mock.lockUpdateJobSetDb.Unlock() - return mock.UpdateJobSetDbFunc(ctx, queue, jobSet, fromMessageId) -} - -// UpdateJobSetDbCalls gets all the calls that were made to UpdateJobSetDb. -// Check the length with: -// -// len(mockedSQLJobService.UpdateJobSetDbCalls()) -func (mock *SQLJobServiceMock) UpdateJobSetDbCalls() []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string -} { - var calls []struct { - Ctx context.Context - Queue string - JobSet string - FromMessageId string - } - mock.lockUpdateJobSetDb.RLock() - calls = mock.calls.UpdateJobSetDb - mock.lockUpdateJobSetDb.RUnlock() - return calls -} diff --git a/internal/jobservice/repository/sql_job_service_test.go b/internal/jobservice/repository/sql_job_service_test.go deleted file mode 100644 index de883d85ca4..00000000000 --- a/internal/jobservice/repository/sql_job_service_test.go +++ /dev/null @@ -1,495 +0,0 @@ -package repository - -import ( - "context" - "fmt" - "os" - "sync" - "testing" - "time" - - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/armadaproject/armada/internal/jobservice/configuration" - "github.com/armadaproject/armada/pkg/api/jobservice" -) - -const purgeTime = 0 - -func TestConstructInMemoryDoesNotExist(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseExpected := &jobservice.JobServiceResponse{ - State: jobservice.JobServiceResponse_JOB_ID_NOT_FOUND, - } - err := r.SubscribeJobSet(ctx, "test", "job-set-1", "test") - require.NoError(t, err) - jobStatus := NewJobStatus("test", "job-set-1", "job-id", *responseExpected) - err = r.UpdateJobServiceDb(ctx, jobStatus) - require.NoError(t, err) - - resp, err := r.GetJobStatus(ctx, "job-set-1") - assert.NoError(t, err) - assert.Equal(t, resp, responseExpected) - }) -} - -func TestSubscriptionError(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - err := r.SubscribeJobSet(ctx, "queue-1", "job-set-1", "") - require.NoError(t, err) - err = r.SetSubscriptionError(ctx, "queue-1", "job-set-1", "conn-error", "test") - require.NoError(t, err) - conErr, subErr := r.GetSubscriptionError(ctx, "queue-1", "job-set-1") - require.NoError(t, subErr) - assert.Equal(t, conErr, "conn-error") - }) -} - -func TestUpdateJobSetDb(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - err := r.SubscribeJobSet(ctx, "test", "job-set-1", "test") - require.NoError(t, err) - err = r.UpdateJobSetDb(ctx, "test", "job-set-1", "test") - require.NoError(t, err) - }) -} - -func TestConstructInMemoryServiceFailed(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseExpected := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_FAILED, Error: "TestFail"} - - err := r.SubscribeJobSet(ctx, "test", "job-set-1", "test") - require.NoError(t, err) - - jobStatus := NewJobStatus("test", "job-set-1", "job-id", *responseExpected) - - err = r.UpdateJobServiceDb(ctx, jobStatus) - require.NoError(t, err) - - resp, err := r.GetJobStatus(ctx, "job-id") - require.NoError(t, err) - require.Equal(t, resp, responseExpected) - }) -} - -func TestConstructInMemoryServiceNoJob(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseExpected := &jobservice.JobServiceResponse{ - State: jobservice.JobServiceResponse_JOB_ID_NOT_FOUND, - } - resp, err := r.GetJobStatus(ctx, "job-set-1") - require.NoError(t, err) - require.Equal(t, resp, responseExpected) - }) -} - -func TestIsJobSubscribed(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - resp, _, err := r.IsJobSetSubscribed(ctx, "queue-1", "job-set-1") - require.NoError(t, err) - require.False(t, resp) - err = r.SubscribeJobSet(ctx, "queue-1", "job-set-1", "") - require.NoError(t, err) - resp2, _, err := r.IsJobSetSubscribed(ctx, "queue-1", "job-set-1") - require.NoError(t, err) - require.True(t, resp2) - }) -} - -func TestSubscribeList(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - err := r.SubscribeJobSet(ctx, "queue", "job-set-1", "") - require.NoError(t, err) - err = r.SubscribeJobSet(ctx, "queue", "job-set-2", "") - require.NoError(t, err) - - subscribeList, err := r.GetSubscribedJobSets(ctx) - require.NoError(t, err) - for _, val := range subscribeList { - if val.Queue == "queue" && val.JobSetId == "job-set-1" { - require.Equal(t, val.Queue, "queue") - require.Equal(t, val.JobSetId, "job-set-1") - } else if val.Queue == "queue" && val.JobSetId == "job-set-2" { - require.Equal(t, val.Queue, "queue") - require.Equal(t, val.JobSetId, "job-set-2") - } else { - require.True(t, false) - } - } - }) -} - -func TestCleanupJobSetAndJobsIfNonExist(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - rowsAffected, err := r.UnsubscribeJobSet(ctx, "queue", "job-set-1") - require.NoError(t, err) - subscribe, _, err := r.IsJobSetSubscribed(ctx, "queue", "job-set-1") - require.NoError(t, err) - require.False(t, subscribe) - require.Equal(t, rowsAffected, int64(0)) - require.NoError(t, err) - }) -} - -func TestPurgeExpiredJobSets(t *testing.T) { - realPurgeTime := int64(1) - WithSqlServiceRepo(realPurgeTime, func(r SQLJobService) { - ctx := context.Background() - go r.PurgeExpiredJobSets(ctx) - // test multiple iterations of the purging goroutine - for i := 1; i <= 3; i++ { - jobsetId := fmt.Sprintf("job-set-%d", i) - jobId := fmt.Sprintf("job-%d", i) - responseExpected1 := &jobservice.JobServiceResponse{ - State: jobservice.JobServiceResponse_RUNNING, - } - err := r.SubscribeJobSet(ctx, "queue", jobsetId, "") - require.NoError(t, err) - jobStatus1 := NewJobStatus("test", jobsetId, jobId, *responseExpected1) - err = r.UpdateJobServiceDb(ctx, jobStatus1) - require.NoError(t, err) - subscribe, _, err := r.IsJobSetSubscribed(ctx, "queue", jobsetId) - require.True(t, subscribe) - require.NoError(t, err) - response, err := r.GetJobStatus(ctx, jobId) - require.Equal(t, responseExpected1, response) - require.NoError(t, err) - - // wait until the purge ticker starts a new cycle - time.Sleep(time.Duration(realPurgeTime+1) * time.Second) - - subscribe, _, err = r.IsJobSetSubscribed(ctx, "queue", jobsetId) - require.False(t, subscribe) - require.NoError(t, err) - responseExpected2 := &jobservice.JobServiceResponse{ - State: jobservice.JobServiceResponse_JOB_ID_NOT_FOUND, - } - response, err = r.GetJobStatus(ctx, jobId) - require.Equal(t, responseExpected2, response) - require.NoError(t, err) - } - }) -} - -func TestCleanupJobSetAndJobsHappy(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - err := r.SubscribeJobSet(ctx, "queue", "job-set-1", "") - require.NoError(t, err) - respHappy, _, _ := r.IsJobSetSubscribed(ctx, "queue", "job-set-1") - require.True(t, respHappy) - rowsAffected, err := r.UnsubscribeJobSet(ctx, "queue", "job-set-1") - subscribe, _, _ := r.IsJobSetSubscribed(ctx, "queue", "job-set-1") - require.False(t, subscribe) - require.Equal(t, rowsAffected, int64(1)) - require.NoError(t, err) - }) -} - -func TestDeleteJobsInJobSet(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseExpected1 := &jobservice.JobServiceResponse{ - State: jobservice.JobServiceResponse_FAILED, Error: "TestFail", - } - - err := r.SubscribeJobSet(ctx, "test", "job-set-1", "test") - require.NoError(t, err) - - jobStatus1 := NewJobStatus("test", "job-set-1", "job-id", *responseExpected1) - - err = r.UpdateJobServiceDb(ctx, jobStatus1) - require.NoError(t, err) - - jobResponse1, _ := r.GetJobStatus(ctx, "job-id") - require.Equal(t, jobResponse1, responseExpected1) - - rows, err := r.DeleteJobsInJobSet(ctx, "test", "job-set-1") - require.Equal(t, rows, int64(1)) - require.NoError(t, err) - jobResponseDelete1, _ := r.GetJobStatus(ctx, "job-id") - responseDoesNotExist := &jobservice.JobServiceResponse{ - State: jobservice.JobServiceResponse_JOB_ID_NOT_FOUND, - } - require.Equal(t, jobResponseDelete1, responseDoesNotExist) - - rowsEmpty, errEmpty := r.DeleteJobsInJobSet(ctx, "test", "job-set-1") - require.Equal(t, rowsEmpty, int64(0)) - require.NoError(t, errEmpty) - }) -} - -func TestCheckToUnSubscribe(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseExpected1 := &jobservice.JobServiceResponse{ - State: jobservice.JobServiceResponse_FAILED, Error: "TestFail", - } - - err := r.SubscribeJobSet(ctx, "test", "job-set-1", "") - require.NoError(t, err) - - jobStatus1 := NewJobStatus("test", "job-set-1", "job-id", *responseExpected1) - - err = r.UpdateJobServiceDb(ctx, jobStatus1) - require.NoError(t, err) - - subscribe, _, err := r.IsJobSetSubscribed(ctx, "test", "job-set-1") - require.NoError(t, err) - assert.True(t, subscribe) - flag, errTrue := r.CheckToUnSubscribe(ctx, "test", "job-set-1", time.Second*time.Duration(10000)) - require.NoError(t, errTrue) - assert.False(t, flag) - }) -} - -func TestUnsubscribe(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - err := r.SubscribeJobSet(ctx, "test", "testjobset", "") - require.NoError(t, err) - numberOfJobSets, err := r.UnsubscribeJobSet(ctx, "test", "testjobset") - require.NoError(t, err) - assert.Equal(t, numberOfJobSets, int64(1)) - subscribe, _, err := r.IsJobSetSubscribed(ctx, "test", "testjobset") - require.NoError(t, err) - assert.False(t, subscribe) - }) -} - -func TestUpdateJobSetTime(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - err := r.SubscribeJobSet(ctx, "test", "job-set-1", "") - require.NoError(t, err) - err = r.UpdateJobSetDb(ctx, "test", "job-set-1", "") - require.NoError(t, err) - }) -} - -func TestGetJobStatusAllStates(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseFailed := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_FAILED, Error: "TestFail"} - responseSuccess := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUCCEEDED} - responseDuplicate := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_DUPLICATE_FOUND} - responseRunning := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_RUNNING} - responseSubmitted := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUBMITTED} - responseCancelled := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_CANCELLED} - responseDoesNotExist := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_JOB_ID_NOT_FOUND} - - err := r.SubscribeJobSet(ctx, "test", "job-set-1", "test") - require.NoError(t, err) - - jobStatus1 := NewJobStatus("test", "job-set-1", "job-id", *responseFailed) - jobStatus2 := NewJobStatus("test", "job-set-1", "job-id-2", *responseSuccess) - jobStatus3 := NewJobStatus("test", "job-set-1", "job-id-3", *responseDuplicate) - jobStatus4 := NewJobStatus("test", "job-set-1", "job-id-4", *responseRunning) - jobStatus5 := NewJobStatus("test", "job-set-1", "job-id-5", *responseSubmitted) - jobStatus6 := NewJobStatus("test", "job-set-1", "job-id-6", *responseCancelled) - jobStatus7 := NewJobStatus("test", "job-set-1", "job-id-7", *responseDoesNotExist) - - err = r.UpdateJobServiceDb(ctx, jobStatus1) - require.NoError(t, err) - err = r.UpdateJobServiceDb(ctx, jobStatus2) - require.NoError(t, err) - err = r.UpdateJobServiceDb(ctx, jobStatus3) - require.NoError(t, err) - err = r.UpdateJobServiceDb(ctx, jobStatus4) - require.NoError(t, err) - err = r.UpdateJobServiceDb(ctx, jobStatus5) - require.NoError(t, err) - err = r.UpdateJobServiceDb(ctx, jobStatus6) - require.NoError(t, err) - err = r.UpdateJobServiceDb(ctx, jobStatus7) - require.NoError(t, err) - - actualFailed, errFailed := r.GetJobStatus(ctx, "job-id") - actualSuccess, errSuccess := r.GetJobStatus(ctx, "job-id-2") - actualDuplicate, errDup := r.GetJobStatus(ctx, "job-id-3") - actualRunning, errRunning := r.GetJobStatus(ctx, "job-id-4") - actualSubmitted, errSubmitted := r.GetJobStatus(ctx, "job-id-5") - actualCancelled, errCancel := r.GetJobStatus(ctx, "job-id-6") - actualNotExist, errNotExist := r.GetJobStatus(ctx, "job-id-7") - - require.NoError(t, errFailed) - require.Equal(t, responseFailed, actualFailed) - require.NoError(t, errSuccess) - require.Equal(t, responseSuccess, actualSuccess) - require.NoError(t, errDup) - require.Equal(t, responseDuplicate, actualDuplicate) - require.NoError(t, errRunning) - require.Equal(t, responseRunning, actualRunning) - require.NoError(t, errSubmitted) - require.Equal(t, responseSubmitted, actualSubmitted) - require.NoError(t, errCancel) - require.Equal(t, responseCancelled, actualCancelled) - require.NoError(t, errNotExist) - require.Equal(t, responseDoesNotExist, actualNotExist) - }) -} - -func TestDeleteJobsBeforePersistingRaceError(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseSuccess := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUCCEEDED} - noExist := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_JOB_ID_NOT_FOUND} - var expectedNumberOfJobs int64 = 1 - err := r.SubscribeJobSet(ctx, "test-race", "job-set-race", "") - require.NoError(t, err) - jobStatus1 := NewJobStatus("test-race", "job-set-race", "job-race", *responseSuccess) - err = r.UpdateJobServiceDb(ctx, jobStatus1) - require.NoError(t, err) - numberOfJobs, deleteErr := r.DeleteJobsInJobSet(ctx, "test-race", "job-set-race") - assert.Equal(t, expectedNumberOfJobs, numberOfJobs) - require.NoError(t, deleteErr) - actualSuccess, actualError := r.GetJobStatus(ctx, "job-race") - assert.Equal(t, actualSuccess, noExist) - require.NoError(t, actualError) - sqlNoExist, sqlError := r.GetJobStatus(ctx, "job-race") - assert.Equal(t, sqlNoExist, noExist) - require.NoError(t, sqlError) - }) -} - -func TestGetJobStatusAfterPersisting(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseSuccess := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUCCEEDED} - - err := r.SubscribeJobSet(ctx, "queue", "job-set-1", "") - require.NoError(t, err) - - jobStatus1 := NewJobStatus("test", "job-set-1", "job-id", *responseSuccess) - err = r.UpdateJobServiceDb(ctx, jobStatus1) - require.NoError(t, err) - actual, actualErr := r.GetJobStatus(ctx, "job-id") - assert.Nil(t, actualErr) - assert.Equal(t, actual, responseSuccess) - }) -} - -func TestDuplicateIdDatabaseInsert(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseRunning := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_RUNNING} - responseSuccess := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_SUCCEEDED} - - err := r.SubscribeJobSet(ctx, "queue", "job-set-1", "") - require.NoError(t, err) - - jobStatus1 := NewJobStatus("test", "job-set-1", "job-id", *responseRunning) - err = r.UpdateJobServiceDb(ctx, jobStatus1) - require.NoError(t, err) - actualSql, actualErr := r.GetJobStatus(ctx, "job-id") - assert.Equal(t, actualSql, responseRunning) - require.NoError(t, actualErr) - jobStatus2 := NewJobStatus("test", "job-set-1", "job-id", *responseSuccess) - err = r.UpdateJobServiceDb(ctx, jobStatus2) - require.NoError(t, err) - actualSuccessSql, actualSuccessErr := r.GetJobStatus(ctx, "job-id") - assert.Equal(t, actualSuccessSql, responseSuccess) - require.NoError(t, actualSuccessErr) - }) -} - -func TestHealthCheck(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - healthCheck, err := r.HealthCheck(context.Background()) - assert.True(t, healthCheck) - require.NoError(t, err) - }) -} - -// This test will fail if sqlite writes are not serialised somehow due to -// SQLITE_BUSY errors. -func TestConcurrentJobStatusUpdating(t *testing.T) { - WithSqlServiceRepo(purgeTime, func(r SQLJobService) { - ctx := context.Background() - responseRunning := &jobservice.JobServiceResponse{State: jobservice.JobServiceResponse_RUNNING} - - concurrency := 10 - wg := sync.WaitGroup{} - wg.Add(concurrency) - - startWg := sync.WaitGroup{} - startWg.Add(1) - - err := r.SubscribeJobSet(ctx, "queue", "job-set-1", "") - require.NoError(t, err) - - for i := 0; i < concurrency; i++ { - go func(num int) { - defer wg.Done() - - jobId := fmt.Sprintf("job-id-%d", num) - jobStatus := NewJobStatus("test", "job-set-1", jobId, *responseRunning) - - startWg.Wait() - err := r.UpdateJobServiceDb(ctx, jobStatus) - assert.Nil(t, err) - actualSql, actualErr := r.GetJobStatus(ctx, jobId) - assert.Equal(t, actualSql, responseRunning) - assert.Nil(t, actualErr) - }(i) - } - - startWg.Done() - wg.Wait() - }) -} - -func WithSqlServiceRepo(purgeTime int64, action func(r SQLJobService)) { - var repo SQLJobService - config := &configuration.JobServiceConfiguration{ - PurgeJobSetTime: purgeTime, - } - log := log.WithField("JobService", "Startup") - - if os.Getenv("JSDBTYPE") == "sqlite" { - config.DatabaseType = "sqlite" - config.DatabasePath = "test.db" - } else if os.Getenv("JSDBTYPE") == "postgres" { - config.DatabaseType = "postgres" - config.PostgresConfig = configuration.PostgresConfig{ - PoolMaxOpenConns: 20, - PoolMaxIdleConns: 5, - PoolMaxConnLifetime: 30 * time.Second, - Connection: map[string]string{ - "host": "localhost", - "port": "5432", - "user": "postgres", - "password": "psw", - "dbname": "postgres", - "sslmode": "disable", - }, - } - } - - err, repo, dbCallbackFn := NewSQLJobService(config, log) - if err != nil { - panic(err) - } - defer dbCallbackFn() - - repo.Setup(context.Background()) - action(repo) - - if config.DatabaseType == "sqlite" { - // Besides the base sqlite storage file (e.g. "test.db"), there - // are also two others to be removed ("test.db-shm", "test.db-wal") - for _, suffix := range []string{"", "-shm", "-wal"} { - os.Remove(config.DatabasePath + suffix) - } - } -} diff --git a/internal/jobservice/repository/sqlite.go b/internal/jobservice/repository/sqlite.go deleted file mode 100644 index 835788e841e..00000000000 --- a/internal/jobservice/repository/sqlite.go +++ /dev/null @@ -1,397 +0,0 @@ -package repository - -import ( - "context" - "database/sql" - "errors" - "fmt" - "os" - "path/filepath" - "sync" - "time" - - _ "modernc.org/sqlite" - - log "github.com/sirupsen/logrus" - - "github.com/armadaproject/armada/internal/jobservice/configuration" - js "github.com/armadaproject/armada/pkg/api/jobservice" -) - -// JSRepoSQLite for persisting to DB. -type JSRepoSQLite struct { - jobServiceConfig *configuration.JobServiceConfiguration - db *sql.DB - lock sync.RWMutex -} - -func NewJSRepoSQLite(config *configuration.JobServiceConfiguration, log *log.Entry) (error, *JSRepoSQLite, func()) { - var err error - - dbDir := filepath.Dir(config.DatabasePath) - if _, err := os.Stat(dbDir); os.IsNotExist(err) { - if errMkDir := os.Mkdir(dbDir, 0o755); errMkDir != nil { - errMsg := fmt.Sprintf("error: could not make directory at %s for sqlite db: %v", dbDir, errMkDir) - return errors.New(errMsg), nil, func() {} - } - } - - sqliteDb, err := sql.Open("sqlite", config.DatabasePath) - if err != nil { - errMsg := fmt.Sprintf("error opening sqlite DB from %s %v", config.DatabasePath, err) - return errors.New(errMsg), nil, func() {} - } - - return nil, &JSRepoSQLite{jobServiceConfig: config, db: sqliteDb}, func() { - if err := sqliteDb.Close(); err != nil { - log.Warnf("error closing database: %v", err) - } - } -} - -// Set up the DB for use, create tables -func (s *JSRepoSQLite) Setup(ctx context.Context) { - s.lock.Lock() - defer s.lock.Unlock() - - setupStmts := []string{ - "PRAGMA journal_mode=WAL", - `PRAGMA foreign_keys = ON`, - `DROP TABLE IF EXISTS jobs`, - `DROP TABLE IF EXISTS jobsets`, - `CREATE TABLE jobsets ( - Queue TEXT, - Id TEXT, - Timestamp INT, - ConnectionError TEXT, - FromMessageId TEXT, - UNIQUE(Queue,Id), - PRIMARY KEY(Id) - )`, - `CREATE INDEX idx_jobsets_timestamp ON jobsets (Timestamp)`, - `CREATE TABLE jobs ( - Queue TEXT, - JobSetId TEXT, - Id TEXT, - JobResponseState TEXT, - JobResponseError TEXT, - Timestamp INT, - PRIMARY KEY(Id), - FOREIGN KEY(JobSetId) REFERENCES jobsets(Id) ON DELETE CASCADE - )`, - `CREATE INDEX idx_job_set_queue ON jobs (Queue, JobSetId)`, - `CREATE INDEX idx_jobs_timestamp ON jobs (Timestamp)`, - `DROP TRIGGER IF EXISTS trigger_delete_expired_jobsets`, - } - - for _, stmt := range setupStmts { - _, err := s.db.Exec(stmt) - if err != nil { - panic(err) - } - } -} - -// Get the JobStatus given the jodId -func (s *JSRepoSQLite) GetJobStatus(ctx context.Context, jobId string) (*js.JobServiceResponse, error) { - s.lock.Lock() - defer s.lock.Unlock() - - var queue, jobSetId, jobState, jobError string - sqlStmt := "SELECT Queue, JobSetId, JobResponseState, JobResponseError FROM jobs WHERE Id = ?" - - row := s.db.QueryRow(sqlStmt, jobId) - err := row.Scan(&queue, &jobSetId, &jobState, &jobError) - - if err == sql.ErrNoRows { - return &js.JobServiceResponse{State: js.JobServiceResponse_JOB_ID_NOT_FOUND}, nil - } else if err != nil { - return nil, err - } - - // indicate connnection error for jobset/queue subscription where present - connErr, err := s.GetSubscriptionError(ctx, queue, jobSetId) - if err != nil { - return nil, err - } - if connErr != "" { - return &js.JobServiceResponse{ - Error: connErr, - State: js.JobServiceResponse_CONNECTION_ERR, - }, nil - } - - jobJSRState, err := JobStateStrToJSRState(jobState) - if err != nil { - return nil, err - } - - return &js.JobServiceResponse{Error: jobError, State: jobJSRState}, nil -} - -// Update database with JobTable. -func (s *JSRepoSQLite) UpdateJobServiceDb(ctx context.Context, jobTable *JobStatus) error { - // SQLite only allows one write at a time. Therefore we must serialize - // writes in order to avoid SQL_BUSY errors. - s.lock.Lock() - defer s.lock.Unlock() - - sqlStmt := "INSERT OR REPLACE INTO jobs VALUES (?, ?, ?, ?, ?, ?)" - stmt, err := s.db.Prepare(sqlStmt) - if err != nil { - return err - } - defer stmt.Close() - _, errExec := stmt.Exec(jobTable.queue, jobTable.jobSetId, jobTable.jobId, - jobTable.jobResponse.State.String(), jobTable.jobResponse.Error, jobTable.timeStamp) - return errExec -} - -// We should check if a JobSet exists first before updating the database and return an error if it doesn't exist. -// However, The only caller of this function, in jobservice/server/server.go, does this check before calling. -// Adding the check here will be redundant and a performance botteneck. -// TODO: We should descend the check here and adjust the JobSet subscription logic in jobservice/server/server.go -func (s *JSRepoSQLite) UpdateJobSetDb(ctx context.Context, queue string, jobSet string, fromMessageId string) error { - s.lock.Lock() - defer s.lock.Unlock() - - sqlStmt := "INSERT OR REPLACE INTO jobsets VALUES(?, ?, ?, ?, ?)" - - jobSetState, err := s.db.Prepare(sqlStmt) - if err != nil { - return err - } - defer jobSetState.Close() - _, jobSetErr := jobSetState.Exec(queue, jobSet, time.Now().Unix(), "", &fromMessageId) - if jobSetErr != nil { - return jobSetErr - } - return nil -} - -func (s *JSRepoSQLite) HealthCheck(ctx context.Context) (bool, error) { - s.lock.Lock() - defer s.lock.Unlock() - - row := s.db.QueryRow("SELECT 1") - var col int - err := row.Scan(&col) - if err == nil { - return true, nil - } else { - return false, fmt.Errorf("SQL health check failed: %v", err) - } -} - -// Check if JobSet is in our map. -func (s *JSRepoSQLite) IsJobSetSubscribed(ctx context.Context, queue string, jobSet string) (bool, string, error) { - s.lock.Lock() - defer s.lock.Unlock() - - sqlStmt := "SELECT Queue, Id, FromMessageId FROM jobsets WHERE Queue = ? AND Id = ?" - row := s.db.QueryRow(sqlStmt, queue, jobSet) - var queueScan, jobSetIdScan, fromMessageId string - - err := row.Scan(&queueScan, &jobSetIdScan, &fromMessageId) - - if err == sql.ErrNoRows { - return false, "", nil - } else if err != nil { - return false, "", err - } - return true, fromMessageId, nil -} - -// Clear subscription error if present -func (s *JSRepoSQLite) AddMessageIdAndClearSubscriptionError(ctx context.Context, queue string, - jobSet string, fromMessageId string, -) error { - return s.SetSubscriptionError(ctx, queue, jobSet, "", fromMessageId) -} - -// Set subscription error if present -func (s *JSRepoSQLite) SetSubscriptionError(ctx context.Context, queue string, jobSet string, - connErr string, fromMessageId string, -) error { - s.lock.Lock() - defer s.lock.Unlock() - - sqlStmt := "INSERT OR REPLACE INTO jobsets VALUES(?, ?, ?, ?, ?)" - jobSetState, err := s.db.Prepare(sqlStmt) - if err != nil { - return err - } - defer jobSetState.Close() - - subscribeTable := NewSubscribeTable(queue, jobSet) - _, jobSetErr := jobSetState.Exec(subscribeTable.queue, jobSet, subscribeTable.lastRequestTimeStamp, - connErr, fromMessageId) - if jobSetErr != nil { - return jobSetErr - } - return jobSetErr -} - -// Get subscription error if present -func (s *JSRepoSQLite) GetSubscriptionError(ctx context.Context, queue string, jobSet string) (string, error) { - sqlStmt := "SELECT ConnectionError FROM jobsets WHERE Queue = ? AND Id = ?" - var connError string - - row := s.db.QueryRow(sqlStmt, queue, jobSet) - err := row.Scan(&connError) - - if err == sql.ErrNoRows { - return "", nil - } else if err != nil { - return "", err - } - return connError, nil -} - -// Mark our JobSet as being subscribed -// SubscribeTable contains Queue, JobSet and time when it was created. -func (s *JSRepoSQLite) SubscribeJobSet(ctx context.Context, queue string, jobSet string, fromMessageId string) error { - s.lock.Lock() - defer s.lock.Unlock() - - sqlStmt := "INSERT OR REPLACE INTO jobsets VALUES(?, ?, ?, ?, ?)" - - jobSetState, err := s.db.Prepare(sqlStmt) - if err != nil { - return err - } - defer jobSetState.Close() - subscribeTable := NewSubscribeTable(queue, jobSet) - _, jobSetErr := jobSetState.Exec(subscribeTable.queue, subscribeTable.jobSet, - subscribeTable.lastRequestTimeStamp, "", fromMessageId) - return jobSetErr -} - -// Checks JobSet table to make determine if we should unsubscribe from JobSet -// configTimeWithoutUpdates is a configurable value that is read from the config -// We allow unsubscribing if the jobset hasn't been updated in configTime -// TODO implement this -func (s *JSRepoSQLite) CheckToUnSubscribe(ctx context.Context, queue string, jobSet string, - configTimeWithoutUpdates time.Duration, -) (bool, error) { - jobSetFound, _, err := s.IsJobSetSubscribed(ctx, queue, jobSet) - if err != nil { - return false, nil - } - if !jobSetFound { - return false, nil - } - - s.lock.Lock() - defer s.lock.Unlock() - - sqlStmt := "SELECT Timestamp FROM jobsets WHERE Queue = ? AND Id = ?" - row := s.db.QueryRow(sqlStmt, queue, jobSet) - var timeStamp int64 - - timeErr := row.Scan(&timeStamp) - - if timeErr == sql.ErrNoRows { - return false, nil - } else if err != nil { - return false, err - } - - currentTime := time.Now() - lastUpdate := time.Unix(timeStamp, 0) - if currentTime.After(lastUpdate.Add(configTimeWithoutUpdates)) { - return true, nil - } - - return false, nil -} - -// Deletes the corresponding jobset along with it's associated jobs due to -// the CASCADE DELETE constraint on the foreign-key relationship. -func (s *JSRepoSQLite) UnsubscribeJobSet(ctx context.Context, queue, jobSet string) (int64, error) { - s.lock.Lock() - defer s.lock.Unlock() - - sqlStmt := "DELETE FROM jobsets WHERE Queue = ? AND Id = ?" - - result, err := s.db.Exec(sqlStmt, queue, jobSet) - if err != nil { - return 0, err - } - return result.RowsAffected() -} - -// Delete Jobs in the database -func (s *JSRepoSQLite) DeleteJobsInJobSet(ctx context.Context, queue string, jobSet string) (int64, error) { - s.lock.Lock() - defer s.lock.Unlock() - - sqlStmt := "DELETE FROM jobs WHERE Queue = ? AND JobSetId = ?" - - result, err := s.db.Exec(sqlStmt, queue, jobSet) - if err != nil { - return 0, err - } - return result.RowsAffected() -} - -func (s *JSRepoSQLite) GetSubscribedJobSets(ctx context.Context) ([]SubscribedTuple, error) { - s.lock.Lock() - defer s.lock.Unlock() - - rows, err := s.db.Query("SELECT Queue, Id, FromMessageId FROM jobsets") - if err != nil { - return nil, err - } - defer rows.Close() - - var tuples []SubscribedTuple - - // Loop through rows, using Scan to assign column data to struct fields. - for rows.Next() { - var st SubscribedTuple - if err := rows.Scan(&st.Queue, &st.JobSetId, &st.FromMessageId); err != nil { - return tuples, err - } - tuples = append(tuples, st) - } - if err = rows.Err(); err != nil { - return tuples, err - } - return tuples, nil -} - -// PurgeExpiredJobSets purges all expired Jobs/JobSets from the database -// An expired Job/JobSet is a Job/JobSet that has not been updated within the specified PurgeJobSetTime period. -func (s *JSRepoSQLite) PurgeExpiredJobSets(ctx context.Context) { - jobSetStmt := fmt.Sprintf(`DELETE FROM jobsets WHERE Timestamp < (UNIXEPOCH() - %d);`, s.jobServiceConfig.PurgeJobSetTime) - jobStmt := fmt.Sprintf(`DELETE FROM jobs WHERE Timestamp < (UNIXEPOCH() - %d);`, s.jobServiceConfig.PurgeJobSetTime) - ticker := time.NewTicker(time.Duration(s.jobServiceConfig.PurgeJobSetTime) * time.Second) - log := log.WithField("JobService", "ExpiredJobSetsPurge") - - log.Info("Starting purge of expired jobsets") - for range ticker.C { - s.lock.Lock() - result, jobSetErr := s.db.Exec(jobSetStmt) - if jobSetErr != nil { - log.Error("error deleting expired jobsets: ", jobSetErr) - } else { - count, err := result.RowsAffected() - if err != nil { - log.Error("error getting affected rows for expired jobsets delete operation: ", err) - } - log.Debugf("Deleted %d expired jobsets", count) - } - result, jobErr := s.db.Exec(jobStmt) - if jobErr != nil { - log.Error("error deleting expired jobs: ", jobErr) - } else { - count, err := result.RowsAffected() - if err != nil { - log.Error("error getting affected rows for expired jobs delete operation: ", err) - } - log.Debugf("Deleted %d expired jobs", count) - } - s.lock.Unlock() - } -} diff --git a/internal/jobservice/repository/subscribe_table.go b/internal/jobservice/repository/subscribe_table.go deleted file mode 100644 index d741010d271..00000000000 --- a/internal/jobservice/repository/subscribe_table.go +++ /dev/null @@ -1,13 +0,0 @@ -package repository - -import "time" - -type SubscribeTable struct { - queue string - jobSet string - lastRequestTimeStamp int64 -} - -func NewSubscribeTable(queue string, jobSet string) *SubscribeTable { - return &SubscribeTable{queue: queue, jobSet: jobSet, lastRequestTimeStamp: time.Now().Unix()} -} diff --git a/internal/jobservice/server/server.go b/internal/jobservice/server/server.go deleted file mode 100644 index 06dedfa1443..00000000000 --- a/internal/jobservice/server/server.go +++ /dev/null @@ -1,82 +0,0 @@ -package server - -import ( - "context" - - "github.com/gogo/protobuf/types" - log "github.com/sirupsen/logrus" - - "github.com/armadaproject/armada/internal/jobservice/configuration" - "github.com/armadaproject/armada/internal/jobservice/events" - "github.com/armadaproject/armada/internal/jobservice/repository" - - js "github.com/armadaproject/armada/pkg/api/jobservice" -) - -type JobServiceServer struct { - jobServiceConfig *configuration.JobServiceConfiguration - jobRepository repository.SQLJobService - newSubChan chan *repository.SubscribedTuple -} - -func NewJobService(config *configuration.JobServiceConfiguration, sqlService repository.SQLJobService) *JobServiceServer { - return &JobServiceServer{ - jobServiceConfig: config, - jobRepository: sqlService, - // TODO: What's a reasonable buffer length? - newSubChan: make(chan *repository.SubscribedTuple, 1000), - } -} - -func (s *JobServiceServer) GetNewSubscriptionChannel() <-chan *repository.SubscribedTuple { - return s.newSubChan -} - -func (s *JobServiceServer) GetJobStatus(ctx context.Context, opts *js.JobServiceRequest) (*js.JobServiceResponse, error) { - requestFields := log.Fields{ - "job_id": opts.JobId, - "job_set_id": opts.JobSetId, - "queue": opts.Queue, - } - - jobSetExists, fromMessageId, err := s.jobRepository.IsJobSetSubscribed(ctx, opts.Queue, opts.JobSetId) - if err != nil { - log.Error("error checking if job is subscribed", err) - } - if !jobSetExists { - errsubscribe := s.jobRepository.SubscribeJobSet(ctx, opts.Queue, opts.JobSetId, fromMessageId) - if errsubscribe != nil { - log.Error("unable to subscribe job set", err) - } else { - s.newSubChan <- &repository.SubscribedTuple{ - JobSetKey: repository.JobSetKey{ - Queue: opts.Queue, - JobSetId: opts.JobSetId, - }, - FromMessageId: fromMessageId, - } - } - log.Infof("Subscribing to queue %s jobset %s messageId %s", opts.Queue, opts.JobSetId, fromMessageId) - } else { - if err := s.jobRepository.UpdateJobSetDb(ctx, opts.Queue, opts.JobSetId, fromMessageId); err != nil { - log.WithFields(requestFields).Warn(err) - } - } - response, err := s.jobRepository.GetJobStatus(ctx, opts.JobId) - if err != nil { - log.WithFields(requestFields).Error(err) - return nil, err - } - - return response, err -} - -func (s *JobServiceServer) Health(ctx context.Context, _ *types.Empty) (*js.HealthCheckResponse, error) { - eventClient := events.NewEventClient(&s.jobServiceConfig.ApiConnection) - _, err := eventClient.Health(context.Background(), &types.Empty{}) - if err != nil { - log.Errorf("health check failed for events with %s", err) - return nil, err - } - return &js.HealthCheckResponse{Status: js.HealthCheckResponse_SERVING}, nil -} diff --git a/magefiles/developer.go b/magefiles/developer.go index 9cb4876f8d5..6954ab16acf 100644 --- a/magefiles/developer.go +++ b/magefiles/developer.go @@ -31,7 +31,6 @@ var defaultComponents = []string{ var allComponents = append( slices.Clone(defaultComponents), - "jobservice", "airflow", ) diff --git a/magefiles/main.go b/magefiles/main.go index e10d4e8035f..0b8756b3201 100644 --- a/magefiles/main.go +++ b/magefiles/main.go @@ -205,7 +205,7 @@ func LocalDev(arg string) error { case "minimal": mg.Deps(mg.F(goreleaserMinimalRelease, "bundle"), Kind, downloadDependencyImages) case "full": - mg.Deps(BuildPython, mg.F(BuildDockers, "bundle, lookout-bundle, jobservice"), Kind, downloadDependencyImages) + mg.Deps(BuildPython, mg.F(BuildDockers, "bundle, lookout-bundle"), Kind, downloadDependencyImages) case "no-build", "debug": mg.Deps(Kind, downloadDependencyImages) default: @@ -315,7 +315,7 @@ func Generate() error { // CI Image to build func BuildCI() error { - ciImage := []string{"bundle", "lookout-bundle", "server", "executor", "armadactl", "testsuite", "lookoutv2", "lookoutingesterv2", "eventingester", "scheduler", "scheduleringester", "binoculars", "jobservice"} + ciImage := []string{"bundle", "lookout-bundle", "server", "executor", "armadactl", "testsuite", "lookoutv2", "lookoutingesterv2", "eventingester", "scheduler", "scheduleringester", "binoculars"} err := goreleaserMinimalRelease(ciImage...) if err != nil { return err diff --git a/magefiles/proto.go b/magefiles/proto.go index fd946984145..a45906c29f0 100644 --- a/magefiles/proto.go +++ b/magefiles/proto.go @@ -98,7 +98,6 @@ func protoGenerate() error { "internal/scheduler/schedulerobjects/*.proto", "internal/scheduler/simulator/*.proto", "pkg/api/binoculars/*.proto", - "pkg/api/jobservice/*.proto", "pkg/executorapi/*.proto", } for _, pattern := range patterns { diff --git a/magefiles/tests.go b/magefiles/tests.go index 11cc3b2b6be..a30ba7b51ad 100644 --- a/magefiles/tests.go +++ b/magefiles/tests.go @@ -77,8 +77,6 @@ func Tests() error { return err } - internalPackages := filterPackages(strings.Fields(packages), "jobservice/repository") - cmd := []string{ "--format", "short-verbose", "--junitfile", "test-reports/unit-tests.xml", @@ -88,7 +86,7 @@ func Tests() error { "-covermode=atomic", "./cmd/...", "./pkg/...", } - cmd = append(cmd, internalPackages...) + cmd = append(cmd, strings.Fields(packages)...) testCmd := exec.Command(Gotestsum, cmd...) @@ -111,16 +109,6 @@ func Tests() error { return err } -func filterPackages(packages []string, filter string) []string { - var filtered []string - for _, pkg := range packages { - if !strings.Contains(pkg, filter) { - filtered = append(filtered, pkg) - } - } - return filtered -} - func runTest(name, outputFileName string) error { cmd := exec.Command(Gotestsum, "--", "-v", name, "-count=1") file, err := os.Create(filepath.Join("test_reports", outputFileName)) diff --git a/pkg/api/jobservice/jobservice.pb.go b/pkg/api/jobservice/jobservice.pb.go deleted file mode 100644 index 71f1b981b82..00000000000 --- a/pkg/api/jobservice/jobservice.pb.go +++ /dev/null @@ -1,1001 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: pkg/api/jobservice/jobservice.proto - -package jobservice - -import ( - context "context" - fmt "fmt" - io "io" - math "math" - math_bits "math/bits" - - proto "github.com/gogo/protobuf/proto" - types "github.com/gogo/protobuf/types" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type HealthCheckResponse_ServingStatus int32 - -const ( - HealthCheckResponse_UNKNOWN HealthCheckResponse_ServingStatus = 0 - HealthCheckResponse_SERVING HealthCheckResponse_ServingStatus = 1 - HealthCheckResponse_NOT_SERVING HealthCheckResponse_ServingStatus = 2 -) - -var HealthCheckResponse_ServingStatus_name = map[int32]string{ - 0: "UNKNOWN", - 1: "SERVING", - 2: "NOT_SERVING", -} - -var HealthCheckResponse_ServingStatus_value = map[string]int32{ - "UNKNOWN": 0, - "SERVING": 1, - "NOT_SERVING": 2, -} - -func (x HealthCheckResponse_ServingStatus) String() string { - return proto.EnumName(HealthCheckResponse_ServingStatus_name, int32(x)) -} - -func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_acaf6279d0169157, []int{0, 0} -} - -// See event.proto for a list of possible events -// We have filtered down these events to only the important ones for a user -type JobServiceResponse_State int32 - -const ( - JobServiceResponse_SUBMITTED JobServiceResponse_State = 0 - JobServiceResponse_DUPLICATE_FOUND JobServiceResponse_State = 1 - JobServiceResponse_RUNNING JobServiceResponse_State = 2 - JobServiceResponse_FAILED JobServiceResponse_State = 3 - JobServiceResponse_SUCCEEDED JobServiceResponse_State = 4 - JobServiceResponse_CANCELLED JobServiceResponse_State = 5 - JobServiceResponse_JOB_ID_NOT_FOUND JobServiceResponse_State = 6 - JobServiceResponse_CONNECTION_ERR JobServiceResponse_State = 7 -) - -var JobServiceResponse_State_name = map[int32]string{ - 0: "SUBMITTED", - 1: "DUPLICATE_FOUND", - 2: "RUNNING", - 3: "FAILED", - 4: "SUCCEEDED", - 5: "CANCELLED", - 6: "JOB_ID_NOT_FOUND", - 7: "CONNECTION_ERR", -} - -var JobServiceResponse_State_value = map[string]int32{ - "SUBMITTED": 0, - "DUPLICATE_FOUND": 1, - "RUNNING": 2, - "FAILED": 3, - "SUCCEEDED": 4, - "CANCELLED": 5, - "JOB_ID_NOT_FOUND": 6, - "CONNECTION_ERR": 7, -} - -func (x JobServiceResponse_State) String() string { - return proto.EnumName(JobServiceResponse_State_name, int32(x)) -} - -func (JobServiceResponse_State) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_acaf6279d0169157, []int{2, 0} -} - -type HealthCheckResponse struct { - Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,proto3,enum=jobservice.HealthCheckResponse_ServingStatus" json:"status,omitempty"` -} - -func (m *HealthCheckResponse) Reset() { *m = HealthCheckResponse{} } -func (m *HealthCheckResponse) String() string { return proto.CompactTextString(m) } -func (*HealthCheckResponse) ProtoMessage() {} -func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_acaf6279d0169157, []int{0} -} -func (m *HealthCheckResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *HealthCheckResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_HealthCheckResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *HealthCheckResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_HealthCheckResponse.Merge(m, src) -} -func (m *HealthCheckResponse) XXX_Size() int { - return m.Size() -} -func (m *HealthCheckResponse) XXX_DiscardUnknown() { - xxx_messageInfo_HealthCheckResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_HealthCheckResponse proto.InternalMessageInfo - -func (m *HealthCheckResponse) GetStatus() HealthCheckResponse_ServingStatus { - if m != nil { - return m.Status - } - return HealthCheckResponse_UNKNOWN -} - -type JobServiceRequest struct { - JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"jobId,omitempty"` - JobSetId string `protobuf:"bytes,2,opt,name=job_set_id,json=jobSetId,proto3" json:"jobSetId,omitempty"` - Queue string `protobuf:"bytes,3,opt,name=queue,proto3" json:"queue,omitempty"` -} - -func (m *JobServiceRequest) Reset() { *m = JobServiceRequest{} } -func (m *JobServiceRequest) String() string { return proto.CompactTextString(m) } -func (*JobServiceRequest) ProtoMessage() {} -func (*JobServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_acaf6279d0169157, []int{1} -} -func (m *JobServiceRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *JobServiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_JobServiceRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *JobServiceRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_JobServiceRequest.Merge(m, src) -} -func (m *JobServiceRequest) XXX_Size() int { - return m.Size() -} -func (m *JobServiceRequest) XXX_DiscardUnknown() { - xxx_messageInfo_JobServiceRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_JobServiceRequest proto.InternalMessageInfo - -func (m *JobServiceRequest) GetJobId() string { - if m != nil { - return m.JobId - } - return "" -} - -func (m *JobServiceRequest) GetJobSetId() string { - if m != nil { - return m.JobSetId - } - return "" -} - -func (m *JobServiceRequest) GetQueue() string { - if m != nil { - return m.Queue - } - return "" -} - -type JobServiceResponse struct { - State JobServiceResponse_State `protobuf:"varint,1,opt,name=state,proto3,enum=jobservice.JobServiceResponse_State" json:"state,omitempty"` - // For failed jobs, this will contain a reason why the job failed - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` -} - -func (m *JobServiceResponse) Reset() { *m = JobServiceResponse{} } -func (m *JobServiceResponse) String() string { return proto.CompactTextString(m) } -func (*JobServiceResponse) ProtoMessage() {} -func (*JobServiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_acaf6279d0169157, []int{2} -} -func (m *JobServiceResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *JobServiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_JobServiceResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *JobServiceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_JobServiceResponse.Merge(m, src) -} -func (m *JobServiceResponse) XXX_Size() int { - return m.Size() -} -func (m *JobServiceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_JobServiceResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_JobServiceResponse proto.InternalMessageInfo - -func (m *JobServiceResponse) GetState() JobServiceResponse_State { - if m != nil { - return m.State - } - return JobServiceResponse_SUBMITTED -} - -func (m *JobServiceResponse) GetError() string { - if m != nil { - return m.Error - } - return "" -} - -func init() { - proto.RegisterEnum("jobservice.HealthCheckResponse_ServingStatus", HealthCheckResponse_ServingStatus_name, HealthCheckResponse_ServingStatus_value) - proto.RegisterEnum("jobservice.JobServiceResponse_State", JobServiceResponse_State_name, JobServiceResponse_State_value) - proto.RegisterType((*HealthCheckResponse)(nil), "jobservice.HealthCheckResponse") - proto.RegisterType((*JobServiceRequest)(nil), "jobservice.JobServiceRequest") - proto.RegisterType((*JobServiceResponse)(nil), "jobservice.JobServiceResponse") -} - -func init() { - proto.RegisterFile("pkg/api/jobservice/jobservice.proto", fileDescriptor_acaf6279d0169157) -} - -var fileDescriptor_acaf6279d0169157 = []byte{ - // 574 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x53, 0xcd, 0x6e, 0xd3, 0x4c, - 0x14, 0x8d, 0xd3, 0x2f, 0xee, 0xd7, 0x5b, 0xda, 0x9a, 0x69, 0x55, 0x55, 0x45, 0x38, 0x28, 0xb0, - 0x00, 0x04, 0xb6, 0x54, 0x58, 0xb1, 0x73, 0x6c, 0xb7, 0xb8, 0xa4, 0xe3, 0xca, 0x49, 0x40, 0x82, - 0x85, 0x65, 0x27, 0x43, 0xe2, 0xb4, 0xc9, 0xb8, 0xf6, 0x18, 0x89, 0x77, 0x60, 0xc1, 0x13, 0x00, - 0x6b, 0x16, 0x3c, 0x07, 0xcb, 0x2e, 0x59, 0x45, 0x28, 0xd9, 0xe5, 0x29, 0xd0, 0x8c, 0x13, 0xc5, - 0x55, 0xf9, 0xd9, 0x79, 0xce, 0x3d, 0xf7, 0x9e, 0x33, 0x67, 0xae, 0xe1, 0x6e, 0x7c, 0xd6, 0xd3, - 0x83, 0x38, 0xd2, 0x07, 0x34, 0x4c, 0x49, 0xf2, 0x2e, 0xea, 0x90, 0xc2, 0xa7, 0x16, 0x27, 0x94, - 0x51, 0x04, 0x4b, 0x64, 0xff, 0x56, 0x8f, 0xd2, 0xde, 0x39, 0xd1, 0x45, 0x25, 0xcc, 0xde, 0xea, - 0x64, 0x18, 0xb3, 0xf7, 0x39, 0xb1, 0xf6, 0x4d, 0x82, 0xed, 0xe7, 0x24, 0x38, 0x67, 0x7d, 0xb3, - 0x4f, 0x3a, 0x67, 0x1e, 0x49, 0x63, 0x3a, 0x4a, 0x09, 0x7a, 0x03, 0x72, 0xca, 0x02, 0x96, 0xa5, - 0x7b, 0xd2, 0x1d, 0xe9, 0xfe, 0xe6, 0xc1, 0x63, 0xad, 0xa0, 0xf1, 0x9b, 0x06, 0xad, 0xc9, 0x6b, - 0xa3, 0x5e, 0x53, 0x34, 0xd5, 0x77, 0x66, 0xe3, 0xaa, 0x92, 0x0f, 0x78, 0x44, 0x87, 0x11, 0x13, - 0x92, 0xde, 0x7c, 0x64, 0xed, 0x19, 0x6c, 0x5c, 0xa1, 0xa3, 0x75, 0x58, 0x6d, 0xe3, 0x17, 0xd8, - 0x7d, 0x85, 0x95, 0x12, 0x3f, 0x34, 0x6d, 0xef, 0xa5, 0x83, 0x8f, 0x14, 0x09, 0x6d, 0xc1, 0x3a, - 0x76, 0x5b, 0xfe, 0x02, 0x28, 0xd7, 0xbe, 0x48, 0x70, 0xf3, 0x98, 0x86, 0xcd, 0xdc, 0x8a, 0x47, - 0x2e, 0x32, 0x92, 0x32, 0xf4, 0x10, 0xe4, 0x01, 0x0d, 0xfd, 0xa8, 0x2b, 0xec, 0xae, 0xd5, 0xb7, - 0x67, 0xe3, 0xea, 0xd6, 0x80, 0x86, 0x4e, 0xb7, 0x20, 0x5f, 0x11, 0x00, 0x7a, 0x0a, 0x3c, 0x1d, - 0x3f, 0x25, 0x8c, 0xf3, 0xcb, 0x82, 0xbf, 0x3b, 0x1b, 0x57, 0xd1, 0x80, 0x8f, 0x65, 0x57, 0x5a, - 0xfe, 0x5f, 0x60, 0xe8, 0x01, 0x54, 0x2e, 0x32, 0x92, 0x91, 0xbd, 0x95, 0xa5, 0x80, 0x00, 0x8a, - 0x02, 0x02, 0xa8, 0x7d, 0x2e, 0x03, 0x2a, 0x5a, 0x9c, 0x47, 0xea, 0x42, 0x85, 0xdf, 0x9f, 0xcc, - 0x13, 0xbd, 0x57, 0x4c, 0xf4, 0x3a, 0x5d, 0xe3, 0xd1, 0x90, 0x5c, 0x47, 0xb4, 0x15, 0x75, 0x04, - 0xc0, 0x2d, 0x91, 0x24, 0xa1, 0xc9, 0xfc, 0x0e, 0x82, 0x2a, 0x80, 0x22, 0x55, 0x00, 0xb5, 0x0f, - 0x12, 0x54, 0xc4, 0x40, 0xb4, 0x01, 0x6b, 0xcd, 0x76, 0xfd, 0xc4, 0x69, 0xb5, 0x6c, 0x4b, 0x29, - 0xa1, 0x6d, 0xd8, 0xb2, 0xda, 0xa7, 0x0d, 0xc7, 0x34, 0x5a, 0xb6, 0x7f, 0xe8, 0xb6, 0xb1, 0xa5, - 0x48, 0xfc, 0x05, 0xbc, 0x36, 0xc6, 0x22, 0x70, 0x04, 0x20, 0x1f, 0x1a, 0x4e, 0xc3, 0xb6, 0x94, - 0x95, 0xbc, 0xd9, 0x34, 0x6d, 0xdb, 0xb2, 0x2d, 0xe5, 0x3f, 0x7e, 0x34, 0x0d, 0x6c, 0xda, 0x0d, - 0x5e, 0xad, 0xa0, 0x1d, 0x50, 0x8e, 0xdd, 0xba, 0xef, 0x58, 0x3e, 0x7f, 0xb2, 0x7c, 0x98, 0x8c, - 0x10, 0x6c, 0x9a, 0x2e, 0xc6, 0xb6, 0xd9, 0x72, 0x5c, 0xec, 0xdb, 0x9e, 0xa7, 0xac, 0x1e, 0x7c, - 0x92, 0x00, 0x96, 0x57, 0x46, 0x27, 0x70, 0xe3, 0x88, 0x30, 0x0e, 0xe4, 0xeb, 0x70, 0xfb, 0x4f, - 0xd1, 0x88, 0xc7, 0xde, 0x57, 0xff, 0x9e, 0x1c, 0x32, 0x40, 0xce, 0x37, 0x14, 0xed, 0x6a, 0xf9, - 0xee, 0x6b, 0x8b, 0xdd, 0xd7, 0x6c, 0x9e, 0xca, 0x7e, 0xf5, 0x1f, 0xdb, 0x5c, 0x1f, 0x7d, 0x9f, - 0xa8, 0xd2, 0xe5, 0x44, 0x95, 0x7e, 0x4e, 0x54, 0xe9, 0xe3, 0x54, 0x2d, 0x5d, 0x4e, 0xd5, 0xd2, - 0x8f, 0xa9, 0x5a, 0x7a, 0x7d, 0xd0, 0x8b, 0x58, 0x3f, 0x0b, 0xb5, 0x0e, 0x1d, 0xea, 0x41, 0x32, - 0x0c, 0xba, 0x41, 0x9c, 0xd0, 0x01, 0xe9, 0xb0, 0xf9, 0x49, 0xbf, 0xfe, 0x7b, 0x7e, 0x2d, 0x57, - 0x0d, 0x51, 0x3b, 0xcd, 0x99, 0x9a, 0x43, 0x35, 0x23, 0x8e, 0x0a, 0xd6, 0x43, 0x59, 0x18, 0x7c, - 0xf2, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x26, 0xf4, 0x4c, 0x08, 0xdd, 0x03, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// JobServiceClient is the client API for JobService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type JobServiceClient interface { - GetJobStatus(ctx context.Context, in *JobServiceRequest, opts ...grpc.CallOption) (*JobServiceResponse, error) - Health(ctx context.Context, in *types.Empty, opts ...grpc.CallOption) (*HealthCheckResponse, error) -} - -type jobServiceClient struct { - cc *grpc.ClientConn -} - -func NewJobServiceClient(cc *grpc.ClientConn) JobServiceClient { - return &jobServiceClient{cc} -} - -func (c *jobServiceClient) GetJobStatus(ctx context.Context, in *JobServiceRequest, opts ...grpc.CallOption) (*JobServiceResponse, error) { - out := new(JobServiceResponse) - err := c.cc.Invoke(ctx, "/jobservice.JobService/GetJobStatus", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *jobServiceClient) Health(ctx context.Context, in *types.Empty, opts ...grpc.CallOption) (*HealthCheckResponse, error) { - out := new(HealthCheckResponse) - err := c.cc.Invoke(ctx, "/jobservice.JobService/Health", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// JobServiceServer is the server API for JobService service. -type JobServiceServer interface { - GetJobStatus(context.Context, *JobServiceRequest) (*JobServiceResponse, error) - Health(context.Context, *types.Empty) (*HealthCheckResponse, error) -} - -// UnimplementedJobServiceServer can be embedded to have forward compatible implementations. -type UnimplementedJobServiceServer struct { -} - -func (*UnimplementedJobServiceServer) GetJobStatus(ctx context.Context, req *JobServiceRequest) (*JobServiceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetJobStatus not implemented") -} -func (*UnimplementedJobServiceServer) Health(ctx context.Context, req *types.Empty) (*HealthCheckResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Health not implemented") -} - -func RegisterJobServiceServer(s *grpc.Server, srv JobServiceServer) { - s.RegisterService(&_JobService_serviceDesc, srv) -} - -func _JobService_GetJobStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(JobServiceRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(JobServiceServer).GetJobStatus(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/jobservice.JobService/GetJobStatus", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(JobServiceServer).GetJobStatus(ctx, req.(*JobServiceRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _JobService_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(types.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(JobServiceServer).Health(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/jobservice.JobService/Health", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(JobServiceServer).Health(ctx, req.(*types.Empty)) - } - return interceptor(ctx, in, info, handler) -} - -var _JobService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "jobservice.JobService", - HandlerType: (*JobServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetJobStatus", - Handler: _JobService_GetJobStatus_Handler, - }, - { - MethodName: "Health", - Handler: _JobService_Health_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "pkg/api/jobservice/jobservice.proto", -} - -func (m *HealthCheckResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *HealthCheckResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *HealthCheckResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Status != 0 { - i = encodeVarintJobservice(dAtA, i, uint64(m.Status)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *JobServiceRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *JobServiceRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *JobServiceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Queue) > 0 { - i -= len(m.Queue) - copy(dAtA[i:], m.Queue) - i = encodeVarintJobservice(dAtA, i, uint64(len(m.Queue))) - i-- - dAtA[i] = 0x1a - } - if len(m.JobSetId) > 0 { - i -= len(m.JobSetId) - copy(dAtA[i:], m.JobSetId) - i = encodeVarintJobservice(dAtA, i, uint64(len(m.JobSetId))) - i-- - dAtA[i] = 0x12 - } - if len(m.JobId) > 0 { - i -= len(m.JobId) - copy(dAtA[i:], m.JobId) - i = encodeVarintJobservice(dAtA, i, uint64(len(m.JobId))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *JobServiceResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *JobServiceResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *JobServiceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Error) > 0 { - i -= len(m.Error) - copy(dAtA[i:], m.Error) - i = encodeVarintJobservice(dAtA, i, uint64(len(m.Error))) - i-- - dAtA[i] = 0x12 - } - if m.State != 0 { - i = encodeVarintJobservice(dAtA, i, uint64(m.State)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintJobservice(dAtA []byte, offset int, v uint64) int { - offset -= sovJobservice(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *HealthCheckResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Status != 0 { - n += 1 + sovJobservice(uint64(m.Status)) - } - return n -} - -func (m *JobServiceRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.JobId) - if l > 0 { - n += 1 + l + sovJobservice(uint64(l)) - } - l = len(m.JobSetId) - if l > 0 { - n += 1 + l + sovJobservice(uint64(l)) - } - l = len(m.Queue) - if l > 0 { - n += 1 + l + sovJobservice(uint64(l)) - } - return n -} - -func (m *JobServiceResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.State != 0 { - n += 1 + sovJobservice(uint64(m.State)) - } - l = len(m.Error) - if l > 0 { - n += 1 + l + sovJobservice(uint64(l)) - } - return n -} - -func sovJobservice(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozJobservice(x uint64) (n int) { - return sovJobservice(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *HealthCheckResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: HealthCheckResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: HealthCheckResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) - } - m.Status = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Status |= HealthCheckResponse_ServingStatus(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipJobservice(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthJobservice - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *JobServiceRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: JobServiceRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: JobServiceRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field JobId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthJobservice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthJobservice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.JobId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field JobSetId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthJobservice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthJobservice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.JobSetId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Queue", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthJobservice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthJobservice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Queue = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipJobservice(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthJobservice - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *JobServiceResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: JobServiceResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: JobServiceResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) - } - m.State = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.State |= JobServiceResponse_State(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowJobservice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthJobservice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthJobservice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Error = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipJobservice(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthJobservice - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipJobservice(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowJobservice - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowJobservice - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowJobservice - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthJobservice - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupJobservice - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthJobservice - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthJobservice = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowJobservice = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupJobservice = fmt.Errorf("proto: unexpected end of group") -) diff --git a/pkg/api/jobservice/jobservice.proto b/pkg/api/jobservice/jobservice.proto deleted file mode 100644 index c4dc04e1424..00000000000 --- a/pkg/api/jobservice/jobservice.proto +++ /dev/null @@ -1,46 +0,0 @@ -syntax = 'proto3'; - -package jobservice; -option go_package = "github.com/armadaproject/armada/pkg/api/jobservice"; -option csharp_namespace = "ArmadaProject.Io.Api.JobService"; - -import "google/protobuf/empty.proto"; - - -message HealthCheckResponse { - enum ServingStatus { - UNKNOWN = 0; - SERVING = 1; - NOT_SERVING = 2; - } - ServingStatus status = 1; -} - -message JobServiceRequest { - string job_id = 1; - string job_set_id = 2; - string queue = 3; -} - -message JobServiceResponse { -// See event.proto for a list of possible events -// We have filtered down these events to only the important ones for a user - enum State { - SUBMITTED = 0; - DUPLICATE_FOUND = 1; - RUNNING = 2; - FAILED = 3; - SUCCEEDED = 4; - CANCELLED = 5; - JOB_ID_NOT_FOUND = 6; - CONNECTION_ERR = 7; - } - State state = 1; -// For failed jobs, this will contain a reason why the job failed - string error = 2; -} - -service JobService { - rpc GetJobStatus (JobServiceRequest) returns (JobServiceResponse); - rpc Health (google.protobuf.Empty) returns (HealthCheckResponse); -} \ No newline at end of file diff --git a/scripts/common.sh b/scripts/common.sh index 120003c094f..c9879dd1b15 100755 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -16,6 +16,5 @@ export image_names=( "armada-scheduler" "armada-scheduler-ingester" "armada-binoculars" - "armada-jobservice" "armadactl" ) diff --git a/testsuite/performance/jobservice/fakearmada/armada.go b/testsuite/performance/jobservice/fakearmada/armada.go deleted file mode 100644 index 73cae1382e6..00000000000 --- a/testsuite/performance/jobservice/fakearmada/armada.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "fmt" - "net" - "sync" - - log "github.com/sirupsen/logrus" - "google.golang.org/grpc" - "google.golang.org/grpc/encoding" - "google.golang.org/grpc/encoding/gzip" - - "github.com/armadaproject/armada/pkg/api" -) - -func ServePerformanceTestArmadaServer(port int) error { - comp := encoding.GetCompressor(gzip.Name) - encoding.RegisterCompressor(comp) - - server := grpc.NewServer([]grpc.ServerOption{}...) - - performanceTestEventServer := NewPerformanceTestEventServer() - - api.RegisterEventServer(server, performanceTestEventServer) - - log.Infof("Armada performanceTestEventServer gRPC server listening on %d", port) - lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) - if err != nil { - return err - } - return server.Serve(lis) -} - -func main() { - var wg sync.WaitGroup - - wg.Add(1) - go func() { - err := ServePerformanceTestArmadaServer(1337) - if err != nil { - fmt.Println(err.Error()) - } - wg.Done() - }() - - wg.Wait() -} diff --git a/testsuite/performance/jobservice/fakearmada/event_server.go b/testsuite/performance/jobservice/fakearmada/event_server.go deleted file mode 100644 index f2f5676291c..00000000000 --- a/testsuite/performance/jobservice/fakearmada/event_server.go +++ /dev/null @@ -1,147 +0,0 @@ -package main - -import ( - "context" - "fmt" - "time" - - "github.com/gogo/protobuf/types" - - "github.com/armadaproject/armada/pkg/api" -) - -type PerformanceTestEventServer struct{} - -func NewPerformanceTestEventServer() *PerformanceTestEventServer { - return &PerformanceTestEventServer{} -} - -// GetJobSetEvents streams back all events associated with a particular job set. -func (s *PerformanceTestEventServer) GetJobSetEvents(request *api.JobSetRequest, stream api.Event_GetJobSetEventsServer) error { - // FIXME: Handle case where watch is not True. - return s.serveSimulatedEvents(request, stream) -} - -func (s *PerformanceTestEventServer) Health(ctx context.Context, cont_ *types.Empty) (*api.HealthCheckResponse, error) { - return &api.HealthCheckResponse{Status: api.HealthCheckResponse_SERVING}, nil -} - -func (s *PerformanceTestEventServer) Watch(req *api.WatchRequest, stream api.Event_WatchServer) error { - request := &api.JobSetRequest{ - Id: req.JobSetId, - Watch: true, - FromMessageId: req.FromId, - Queue: req.Queue, - ErrorIfMissing: true, - } - return s.GetJobSetEvents(request, stream) -} - -type scriptedMessage struct { - Delay time.Duration - MessageFunc func(*api.JobSetRequest) *api.EventMessage -} - -var messageScript = []*scriptedMessage{ - { // Submitted - Delay: time.Duration(1), - MessageFunc: func(request *api.JobSetRequest) *api.EventMessage { - return &api.EventMessage{ - Events: &api.EventMessage_Submitted{ - Submitted: &api.JobSubmittedEvent{ - JobId: "fake_job_id", - JobSetId: request.Id, - Queue: request.Queue, - Created: types.TimestampNow(), - Job: &api.Job{ - Id: "fake_job_id", - ClientId: "", - Queue: request.Queue, - JobSetId: request.Id, - Namespace: "fakeNamespace", - Created: types.TimestampNow(), - }, - }, - }, - } - }, - }, - { // Queued - Delay: time.Duration(time.Second * 1), - MessageFunc: func(request *api.JobSetRequest) *api.EventMessage { - return &api.EventMessage{ - Events: &api.EventMessage_Queued{ - Queued: &api.JobQueuedEvent{ - JobId: "fake_job_id", - JobSetId: request.Id, - Queue: request.Queue, - Created: types.TimestampNow(), - }, - }, - } - }, - }, - { // Running - Delay: time.Duration(time.Second * 1), - MessageFunc: func(request *api.JobSetRequest) *api.EventMessage { - return &api.EventMessage{ - Events: &api.EventMessage_Running{ - Running: &api.JobRunningEvent{ - JobId: "fake_job_id", - JobSetId: request.Id, - Queue: request.Queue, - Created: types.TimestampNow(), - ClusterId: "fakeCluster", - KubernetesId: "fakeK8s", - NodeName: "fakeNode", - PodNumber: 1, - PodName: "fakePod", - PodNamespace: "fakeNamespace", - }, - }, - } - }, - }, - { // Success - Delay: time.Duration(time.Second * 10), - MessageFunc: func(request *api.JobSetRequest) *api.EventMessage { - return &api.EventMessage{ - Events: &api.EventMessage_Succeeded{ - Succeeded: &api.JobSucceededEvent{ - JobId: "fake_job_id", - JobSetId: request.Id, - Queue: request.Queue, - Created: types.TimestampNow(), - ClusterId: "fakeCluster", - KubernetesId: "fakeK8s", - NodeName: "fakeNode", - PodNumber: 1, - PodName: "fakePod", - PodNamespace: "fakeNamespace", - }, - }, - } - }, - }, -} - -func (s *PerformanceTestEventServer) serveSimulatedEvents(request *api.JobSetRequest, stream api.Event_GetJobSetEventsServer) error { - nextId := 1 - - for _, message := range messageScript { - time.Sleep(message.Delay) - err := stream.Send(&api.EventStreamMessage{ - Id: fmt.Sprintf("%d", nextId), - Message: message.MessageFunc(request), - }) - if err != nil { - return err - } - nextId += 1 - } - - // Keep the stream active but don't send anything - time.Sleep(time.Minute * 10) - - return nil -} diff --git a/testsuite/performance/jobservice/jobservice/jobservice.go b/testsuite/performance/jobservice/jobservice/jobservice.go deleted file mode 100644 index 608f779a1c6..00000000000 --- a/testsuite/performance/jobservice/jobservice/jobservice.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "context" - "fmt" - "net/http" - "os" - "os/signal" - "sync" - "time" - - "google.golang.org/grpc/encoding" - "google.golang.org/grpc/encoding/gzip" - - "github.com/armadaproject/armada/internal/jobservice" - "github.com/armadaproject/armada/internal/jobservice/configuration" - "github.com/armadaproject/armada/pkg/client" - - _ "net/http/pprof" -) - -func main() { - var wg sync.WaitGroup - - ctx, cancel := context.WithCancel(context.Background()) - - signalChan := make(chan os.Signal, 1) - signal.Notify(signalChan, os.Interrupt) - - go func() { - select { - case <-ctx.Done(): - return - case <-signalChan: - fmt.Println("Got interrupt, stopping...") - cancel() - return - } - }() - - go func() { - _ = http.ListenAndServe("localhost:6060", nil) - }() - - comp := encoding.GetCompressor(gzip.Name) - encoding.RegisterCompressor(comp) - - outfile, err := os.Create("jobservice.profile") - if err != nil { - fmt.Println(err.Error()) - return - } - defer outfile.Close() - - /* - err = pprof.StartCPUProfile(outfile) - if err != nil { - fmt.Println(err.Error()) - return - }*/ - - js := jobservice.New() - wg.Add(1) - go func() { - os.Setenv("JOBSERVICE_DEBUG", "TRUE") - err := js.StartUp(ctx, &configuration.JobServiceConfiguration{ - GrpcPort: 2000, - MetricsPort: 2001, - HttpPort: 2002, - DatabaseType: "postgres", - ApiConnection: client.ApiConnectionDetails{ - ArmadaUrl: "localhost:1337", - ForceNoTls: true, - }, - PostgresConfig: configuration.PostgresConfig{ - PoolMaxOpenConns: 50, - PoolMaxIdleConns: 10, - PoolMaxConnLifetime: time.Duration(time.Minute * 30), - Connection: map[string]string{ - "host": "localhost", - "port": "5432", - "user": "postgres", - "password": "psw", - "dbname": "postgres", - "sslmode": "disable", - }, - }, - }) - if err != nil { - fmt.Printf("Error starting Job Service: %v\n", err) - } - wg.Done() - }() - - wg.Wait() - - // pprof.StopCPUProfile() -} diff --git a/testsuite/performance/jobservice/jsloadtest.go b/testsuite/performance/jobservice/jsloadtest.go deleted file mode 100644 index 7eac9d40558..00000000000 --- a/testsuite/performance/jobservice/jsloadtest.go +++ /dev/null @@ -1,73 +0,0 @@ -package main - -import ( - "context" - "fmt" - "math/rand" - "sync" - "time" - - "github.com/gogo/protobuf/types" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - - jsgrpc "github.com/armadaproject/armada/pkg/api/jobservice" -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -// TODO: Add arguments to control how the load is applied. -func main() { - ctx := context.Background() - wg := sync.WaitGroup{} - - // Launch a jobservice client to query jobservice about a jobset - conn, err := grpc.Dial("localhost:2000", grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - fmt.Println(err.Error()) - return - } - client := jsgrpc.NewJobServiceClient(conn) - healthResp, err := client.Health(ctx, &types.Empty{}) - if err != nil { - fmt.Println(err.Error()) - return - } - fmt.Println(healthResp.Status.String()) - - prefix := rand.Intn(10000) - - maxJob := 1000 - wg.Add(maxJob) - - for i := 0; i < maxJob; i++ { - go func(n int) { - err := queryJobStatus(ctx, conn, n, prefix) - if err != nil { - fmt.Printf("Error querying job status: %v\n", err) - } - wg.Done() - }(i) - } - - wg.Wait() -} - -func queryJobStatus(ctx context.Context, conn *grpc.ClientConn, n int, prefix int) error { - client := jsgrpc.NewJobServiceClient(conn) - - resp, err := client.GetJobStatus(ctx, &jsgrpc.JobServiceRequest{ - JobId: "fake_job_id", - JobSetId: fmt.Sprintf("%d_new_fake_job_set_id_%d", prefix, n), - Queue: "fake_queue", - }) - if err != nil { - fmt.Println(err.Error()) - return err - } - - fmt.Printf("%s - %d\n", resp.State.String(), n) - return nil -} diff --git a/third_party/airflow/README.md b/third_party/airflow/README.md index fe3bb0c8c18..4a2425d569e 100644 --- a/third_party/airflow/README.md +++ b/third_party/airflow/README.md @@ -134,8 +134,6 @@ python3.8 -m pip install armada-airflow ## Development -From the top level of the repo, you should run `make airflow-operator`. This will generate proto/grpc files in the jobservice folder. - Airflow with the Armada operator can be run alongside the other Armada services via the docker-compose environment. It is manually started in this way: ``` diff --git a/third_party/airflow/docs/source/python_airflow_operator.rst b/third_party/airflow/docs/source/python_airflow_operator.rst index 292302ec778..4893280d0c7 100644 --- a/third_party/airflow/docs/source/python_airflow_operator.rst +++ b/third_party/airflow/docs/source/python_airflow_operator.rst @@ -12,34 +12,26 @@ armada.operators.armada module :undoc-members: :show-inheritance: -armada.operators.armada_deferrable module ------------------------------------------ - -.. automodule:: armada.operators.armada_deferrable - :members: - :undoc-members: - :show-inheritance: - -armada.operators.jobservice module ----------------------------------- +armada.triggers.armada module +----------------------------- -.. automodule:: armada.operators.jobservice +.. automodule:: armada.triggers.armada :members: :undoc-members: :show-inheritance: -armada.operators.jobservice_asyncio module ------------------------------------------- +armada.auth module +----------------------------- -.. automodule:: armada.operators.jobservice_asyncio +.. automodule:: armada.auth :members: :undoc-members: :show-inheritance: -armada.operators.utils module +armada.model module ----------------------------- -.. automodule:: armada.operators.utils +.. automodule:: armada.model :members: :undoc-members: :show-inheritance: diff --git a/tools.yaml b/tools.yaml index b8f058550eb..f055c4d8420 100644 --- a/tools.yaml +++ b/tools.yaml @@ -8,8 +8,6 @@ tools: - github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway@v1.16.0 - github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger@v1.16.0 - github.com/jstemmer/go-junit-report@v1.0.0 -- github.com/sqlc-dev/sqlc/cmd/sqlc@v1.22.0 -- github.com/matryer/moq@v0.3.0 - github.com/mitchellh/gox@v1.0.1 - github.com/wlbr/templify@v0.0.0-20210816202250-7b8044ca19e9 - golang.org/x/tools/cmd/goimports@v0.5.0