fix(app): correct the worker KEDA PostgreSQL scaler (#12055)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Utwo <mihai.legat@gmail.com>
This commit is contained in:
Bruno Ferreira
2026-08-04 10:47:02 +02:00
committed by GitHub
co-authored by Cursor coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Utwo
parent caf27de6ee
commit 2646068e7e
2 changed files with 62 additions and 14 deletions
@@ -18,15 +18,12 @@ spec:
triggers: triggers:
- type: {{ .Values.worker.keda.triggerType }} - type: {{ .Values.worker.keda.triggerType }}
metadata: metadata:
userName: "postgres" userName: {{ .Values.worker.keda.postgresql.userName | quote }}
passwordFromEnv: POSTGRES_ADMIN_PASSWORD passwordFromEnv: {{ .Values.worker.keda.postgresql.passwordFromEnv | quote }}
host: {{ .Release.Name }}-postgresql host: {{ .Values.worker.keda.postgresql.host | default (printf "%s-postgresql.%s.svc.cluster.local" .Release.Name .Release.Namespace) | quote }}
port: {{ .Values.postgresql.port | quote }} port: {{ .Values.worker.keda.postgresql.port | quote }}
dbName: {{ .Values.postgresql.auth.database | quote }} dbName: {{ .Values.worker.keda.postgresql.database | default .Values.postgresql.auth.database | quote }}
sslmode: disable sslmode: {{ .Values.worker.keda.postgresql.sslmode | quote }}
# Query for KEDA to count the number of scans that are in executing, available, or scheduled states, query: {{ .Values.worker.keda.query | quote }}
# where the scheduled time is within the last 2 hours and is before NOW(). Used for scaling workers. targetQueryValue: {{ .Values.worker.keda.targetQueryValue | quote }}
query: >-
SELECT COUNT(*) FROM scans WHERE ((state='executing' OR state='available' OR state='scheduled') and scheduled_at < NOW() and scheduled_at > NOW() - INTERVAL '2 hours')
targetQueryValue: "1"
{{- end }} {{- end }}
+54 -3
View File
@@ -427,10 +427,61 @@ worker:
pollingInterval: 30 pollingInterval: 30
# -- The cooldown period in seconds for scaling # -- The cooldown period in seconds for scaling
cooldownPeriod: 120 cooldownPeriod: 120
# -- The trigger type for scaling (cpu or memory) # -- The KEDA scaler type. Only `postgresql` is supported by the default query below.
triggerType: "postgresql" triggerType: "postgresql"
# -- The target utilization percentage for the worker pods # PostgreSQL connection used by the scaler query. The KEDA operator opens this
value: "50" # connection from its own namespace, so `host` must resolve from there. The
# defaults target the bundled postgresql subchart; set them explicitly when
# using an external database (postgresql.enabled: false).
postgresql:
# -- Scaler database host. Defaults to the bundled "<release>-postgresql.<namespace>.svc.cluster.local" service.
host: ""
# -- Scaler database port.
port: "5432"
# -- Scaler database name. Defaults to `postgresql.auth.database`.
database: ""
# -- User the scaler authenticates as.
userName: "postgres"
# -- Name of an env var on the worker container holding the password.
passwordFromEnv: "POSTGRES_ADMIN_PASSWORD"
# -- sslmode for the scaler connection.
sslmode: "disable"
# -- The scaler divides the query result by this value to get the desired replica count.
targetQueryValue: "1"
# -- Query the scaler runs to measure pending work. It replaces the previous
# 2-hour scheduled-only window, which missed manual scans, older backlogs and
# in-progress scans. Override to tune scaling for your workload.
#
# The default sums three signals:
# 1. Scans executing or available, bounded to rows updated in the last 24h so
# orphaned rows do not pin the worker up, plus scheduled scans that are due
# (no lower bound, so an overdue backlog still scales up).
# 2. Scan tasks published in the last 48h that no worker has finished. A PENDING
# TaskResult is written at publish time (before_task_publish in api/signals.py),
# so Beat's daily publishes are visible even with zero workers. Signal 1 alone
# deadlocks with minReplicas 0: every scan row after the first is created by
# the worker, so once the initial row ages out of the 24h bound there is
# nothing to count and nothing to create more.
# 3. Non-scan tasks pending in the last hour. Provider connection checks,
# deletions, reports and backfills never touch the scans table, so without
# this they are never picked up while the worker is scaled to zero.
# This includes reconcile-orphan-tasks, a Beat watchdog that runs every two
# minutes, so with minReplicas 0 the worker is woken about that often. Add
# it to the excluded task names below, or raise cooldownPeriod, if you would
# rather trade watchdog latency for longer idle periods.
query: >-
SELECT
(SELECT COUNT(*) FROM scans
WHERE (state IN ('executing', 'available') AND updated_at > NOW() - INTERVAL '24 hours')
OR (state = 'scheduled' AND scheduled_at < NOW()))
+ (SELECT COUNT(*) FROM django_celery_results_taskresult
WHERE task_name IN ('scan-perform', 'scan-perform-scheduled')
AND status IN ('PENDING', 'RECEIVED', 'STARTED')
AND date_created > NOW() - INTERVAL '48 hours')
+ (SELECT COUNT(*) FROM django_celery_results_taskresult
WHERE task_name NOT IN ('scan-perform', 'scan-perform-scheduled')
AND status IN ('PENDING', 'RECEIVED', 'STARTED')
AND date_created > NOW() - INTERVAL '1 hour')
worker_beat: worker_beat:
# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ # This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/