apiVersion: apps/v1 kind: Deployment metadata: name: worker namespace: honeydue labels: app.kubernetes.io/name: worker app.kubernetes.io/part-of: honeydue spec: # Asynq's Scheduler is a singleton — running >1 replica fires every cron # task once per replica (duplicate daily digests, onboarding emails, etc.). # Keep at 1 until asynq.PeriodicTaskManager with Redis leader election is # wired in cmd/worker/main.go. replicas: 1 strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 1 selector: matchLabels: app.kubernetes.io/name: worker template: metadata: labels: app.kubernetes.io/name: worker app.kubernetes.io/part-of: honeydue spec: serviceAccountName: worker imagePullSecrets: - name: ghcr-credentials securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 seccompProfile: type: RuntimeDefault containers: - name: worker image: IMAGE_PLACEHOLDER # Replaced by 03-deploy.sh securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] envFrom: - configMapRef: name: honeydue-config env: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: honeydue-secrets key: POSTGRES_PASSWORD - name: SECRET_KEY valueFrom: secretKeyRef: name: honeydue-secrets key: SECRET_KEY - name: EMAIL_HOST_PASSWORD valueFrom: secretKeyRef: name: honeydue-secrets key: EMAIL_HOST_PASSWORD - name: FCM_SERVER_KEY valueFrom: secretKeyRef: name: honeydue-secrets key: FCM_SERVER_KEY - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: honeydue-secrets key: REDIS_PASSWORD optional: true # B2 (Backblaze) credentials. The worker needs these to delete # B2 objects when the pending_uploads cleanup cron reaps # expired upload sessions. Without them the worker falls back # to local-disk storage which fails on this pod's read-only # root filesystem and disables the cleanup cron. - name: B2_KEY_ID valueFrom: secretKeyRef: name: honeydue-secrets key: B2_KEY_ID - name: B2_APP_KEY valueFrom: secretKeyRef: name: honeydue-secrets key: B2_APP_KEY # Observability — workers emit traces (e.g., asynq job spans) to # obs.88oakapps.com over OTLP/HTTP. service.name=honeydue-worker # so api and worker show up as separate services in Jaeger. - name: OBS_TRACES_URL valueFrom: secretKeyRef: name: honeydue-secrets key: OBS_TRACES_URL optional: true - name: OBS_INGEST_TOKEN valueFrom: secretKeyRef: name: honeydue-secrets key: OBS_INGEST_TOKEN optional: true volumeMounts: - name: apns-key mountPath: /secrets/apns readOnly: true - name: tmp mountPath: /tmp resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi livenessProbe: exec: command: ["pgrep", "-f", "/app/worker"] initialDelaySeconds: 15 periodSeconds: 30 timeoutSeconds: 5 volumes: - name: apns-key secret: secretName: honeydue-apns-key items: - key: apns_auth_key.p8 path: apns_auth_key.p8 - name: tmp emptyDir: sizeLimit: 64Mi