# The job poller, on its own so it can be sized and restarted without touching the API. # # Safe at any replica count on Postgres: claiming uses FOR UPDATE SKIP LOCKED, which is # covered by the hundred-job two-worker test in apps/api/src/modules/jobs/scale.test.ts. # One is the default because the queue is small; raise it when the bandeja backs up. apiVersion: apps/v1 kind: Deployment metadata: name: impuestos-worker namespace: impuestos labels: { app: impuestos, component: worker } spec: replicas: 1 selector: matchLabels: { app: impuestos, component: worker } template: metadata: labels: { app: impuestos, component: worker } spec: # A job that is mid-flight when the pod goes is recovered by the stale sweep rather # than lost, but finishing is cheaper than recovering. terminationGracePeriodSeconds: 30 containers: - name: worker image: ghcr.io/example/impuestos-api:latest ports: - name: http containerPort: 4000 env: # ROLE=worker is what starts the poller; JOBS_INLINE only decides whether a # server also runs one. - name: ROLE value: 'worker' envFrom: - configMapRef: { name: impuestos-config } - secretRef: { name: impuestos-secrets } # A worker still serves /healthz and /readyz, which is how the cluster knows the # poller has a database to poll. It is not behind a Service. livenessProbe: httpGet: { path: /healthz, port: http } initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: { path: /readyz, port: http } initialDelaySeconds: 2 periodSeconds: 10 resources: requests: { cpu: 100m, memory: 256Mi } limits: { memory: 512Mi } volumeMounts: - name: tmp mountPath: /tmp securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: { drop: ['ALL'] } volumes: # The root filesystem is read only, so the one place anything may be written is an # empty directory that dies with the pod. Nothing durable belongs here: uploads go # through the storage driver to S3. - name: tmp emptyDir: {}