davidjfrickert opened a new issue, #65350:
URL: https://github.com/apache/airflow/issues/65350

   ### Under which category would you file this issue?
   
   Helm chart
   
   ### Apache Airflow version
   
   3.1.7 -> 3.2.0
   
   ### What happened and how to reproduce it?
   
   Upgraded Airflow from 3.1.7 and 3.2.0. The db migrations pod was stuck for 
20+ minutes.
   
   Some logs:
   
   ```
   2026-04-16T02:51:13.804504Z [info     ] Context impl MySQLImpl.        
[alembic.runtime.migration] loc=migration.py:210
   2026-04-16T02:51:13.804607Z [info     ] Will assume non-transactional DDL. 
[alembic.runtime.migration] loc=migration.py:213
   2026-04-16T02:51:13.806593Z [info     ] Migrating the Airflow database 
(MySQL) [airflow.utils.db] loc=db.py:1179
   2026-04-16T02:51:13.806680Z [info     ] MySQL: Committing session to release 
metadata locks [airflow.utils.db] loc=db.py:794
   2026-04-16T02:58:44.621134Z [info     ] Context impl MySQLImpl.        
[alembic.runtime.migration] loc=migration.py:210
   2026-04-16T02:58:44.621234Z [info     ] Will assume non-transactional DDL. 
[alembic.runtime.migration] loc=migration.py:213
   2026-04-16T02:58:44.687475Z [info     ] Running upgrade cc92b33c6709 -> 
82dbd68e6171, Add composite index (ti_id, id DESC) to task_reschedule. 
[alembic.runtime.migration] loc=migration.py:621
   ```
   
   First, it was stuck for 7.5 minutes even before it started doing any 
migrations, then the actual migration (Add composite index) was stuck for 20+ 
minutes.
   
   The only way to get this to finish was to scale down all pods, which then 
let this migration finish. Is this expected?
   
   We are using MySQL.
   
   Graph of processes waiting for lock. Started migrations around start of this 
graph and ended when scaled down pods and let migration finish.
   <img width="1340" height="281" alt="Image" 
src="https://github.com/user-attachments/assets/337bba0b-ea1a-4c11-84e8-f2c393bc4c2e";
 />
   
   ### What you think should happen instead?
   
   Helm chart should handle migrations cleanly without needing user to scale 
down workloads.
   
   ### Operating System
   
   _No response_
   
   ### Deployment
   
   Official Apache Airflow Helm Chart
   
   ### Apache Airflow Provider(s)
   
   _No response_
   
   ### Versions of Apache Airflow Providers
   
   _No response_
   
   ### Official Helm Chart version
   
   1.20.0 (latest released)
   
   ### Kubernetes Version
   
   v1.30.14
   
   ### Helm Chart configuration
   
   ```
   defaultAirflowTag: "3.2.0"
   airflowVersion: "3.2.0"
   
   executor: "KubernetesExecutor"
   allowPodLaunching: true
   
   # Avoid having the helm chart managing these secret which causes it to 
rotate on upgrades and causes issues for DAGs or web UI access
   jwtSecretName: airflow-jwt-secret
   fernetKeySecretName: airflow-fernet-key
   apiSecretKeySecretName: airflow-api-secret-key
   
   env:
     - name: AIRFLOW__API__EXPOSE_CONFIG
       value: "False"
     - name: AIRFLOW__API__BASE_URL
       value: "https://(redacted)"
     - name: AIRFLOW__EMAIL__EMAIL_BACKEND
       value: "airflow.utils.email.send_email_smtp"
     - name: AIRFLOW__SMTP__SMTP_HOST
       value: "redacted"
     - name: AIRFLOW__SMTP__SMTP_MAIL_FROM
       value: "redacted"
     - name: AIRFLOW__SMTP__SMTP_STARTTLS
       value: "False"
     - name: AIRFLOW__WEBSERVER__SHOW_TRIGGER_FORM_IF_NO_PARAMS
       value: "True"
     - name: AIRFLOW__WEBSERVER__WARN_DEPLOYMENT_EXPOSURE
       value: "False"
   ## in Airflow V2 parallelism=0 meant infinite.
   ## in V3, a value must be supplied
     - name: AIRFLOW__CORE__PARALLELISM
       value: "256"  
   
   # dags are mounted via localPath
   dags:
     persistence:
       enabled: false
   
   logs:
     persistence:
       enabled: true
       #size: 5Gi
       #annotations: {}
       #storageClassName: "rook-cephfs-fs00"
       existingClaim: airflow-logs
   
   redis:
     enabled: false
   
   postgresql:
     enabled: false
   
   statsd:
     enabled: false
   
   extraEnv: |
     - name: AIRFLOW_KUBE_NAMESPACE
       valueFrom:
         fieldRef:
           fieldPath: metadata.namespace
     - name: AIRFLOW_ENV
       valueFrom:
         configMapKeyRef:
           name: airflow.deployment
           key: environment
   
   extraEnvFrom: |
     - secretRef:
         name: airflow-okta-creds
     - secretRef:
         name: airflow-admin-user-pwd
   
   data:
     metadataSecretName: airflow-db-conn
     resultBackendSecretName: airflow-db-conn
   
   # Root-level tolerations and affinity apply to all components (scheduler, 
webserver, triggerer, etc.)
   # including the KubernetesExecutor pod template.
   # If desired to have different rules for the pod template, set 
workers.affinity/workers.tolerations instead.
   # See: 
https://github.com/apache/airflow/blob/main/chart/files/pod-template-file.kubernetes-helm-yaml
   tolerations:
     - key: airflow
       operator: Equal
       value: "true"
       effect: NoSchedule
   
   affinity:
     nodeAffinity:
       preferredDuringSchedulingIgnoredDuringExecution:
         - weight: 100
           preference:
             matchExpressions:
               - key: node-role.kubernetes.io/worker-airflow
                 operator: In
                 values:
                   - "true"
   
   webserver:
     defaultUser:
       enabled: true
       role: Admin
       username: redacted
       firstName: redacted
       lastName: redacted
       email: redacted
   
   # Note: this is only applied on account creation, if account already exists 
details won't be updated
   createUserJob:
     ttlSecondsAfterFinished: 300
     command: ~
     args:
       - "bash"
       - "-c"
       - |-
         exec \
         airflow users create \
             -r "{{ .Values.webserver.defaultUser.role }}" \
             -u "{{ .Values.webserver.defaultUser.username }}" \
             -e "{{ .Values.webserver.defaultUser.email }}" \
             -f "{{ .Values.webserver.defaultUser.firstName }}" \
             -l "{{ .Values.webserver.defaultUser.lastName }}" \
             -p "${AIRFLOW_ADMIN_PASSWORD}"
     applyCustomEnv: true
   
   securityContexts:
     pod:
       runAsUser: 50000
       runAsGroup: 0
       fsGroup: 50000
       # changing permissions operation is slow, especially on big volumes like 
the logs volume
       # so, only change if the root permissions do not match the expected 
permissions
       fsGroupChangePolicy: "OnRootMismatch"
       runAsNonRoot: true
   
   triggerer:
     replicas: 2
     resources:
       requests:
         memory: "500Mi"
         cpu: "1000m"
       limits:
         memory: "1Gi"
         cpu: "2000m"
     affinity:
       nodeAffinity:
         preferredDuringSchedulingIgnoredDuringExecution:
           - weight: 100
             preference:
               matchExpressions:
                 - key: node-role.kubernetes.io/worker-airflow
                   operator: In
                   values:
                     - "true"
       podAntiAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           - labelSelector:
               matchExpressions:
                 - key: component
                   operator: In
                   values:
                     - triggerer
             topologyKey: "kubernetes.io/hostname"
     extraVolumes:
     - name: dags
       hostPath:
         path: redacted
         type: Directory
     extraVolumeMounts:
       - name: dags
         mountPath: /opt/airflow/dags
         readOnly: true
         subPath: dags-v3
   
   scheduler:
     replicas: 2
     resources:
       requests:
         memory: "4Gi"
         cpu: "2"
       limits:
         memory: "8Gi"
         cpu: "4"
     affinity:
       nodeAffinity:
         preferredDuringSchedulingIgnoredDuringExecution:
           - weight: 100
             preference:
               matchExpressions:
                 - key: node-role.kubernetes.io/worker-airflow
                   operator: In
                   values:
                     - "true"
       podAntiAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           - labelSelector:
               matchExpressions:
                 - key: component
                   operator: In
                   values:
                     - scheduler
             topologyKey: "kubernetes.io/hostname"
   
   dagProcessor:
     replicas: 2
     resources:
     # dagProcessor has memory leak increasing around 300MB/day
       requests:
         memory: "4Gi"
         cpu: "1"
       limits:
         memory: "8Gi"
         cpu: "2"
     affinity:
       nodeAffinity:
         preferredDuringSchedulingIgnoredDuringExecution:
           - weight: 100
             preference:
               matchExpressions:
                 - key: node-role.kubernetes.io/worker-airflow
                   operator: In
                   values:
                     - "true"
       podAntiAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           - labelSelector:
               matchExpressions:
                 - key: component
                   operator: In
                   values:
                     - dag-processor
             topologyKey: "kubernetes.io/hostname"
     extraVolumes:
     - name: dags
       hostPath:
         path: redacted
         type: Directory
     extraVolumeMounts:
       - name: dags
         mountPath: /opt/airflow/dags
         readOnly: true
         subPath: dags-v3
   
   apiServer:
     replicas: 2
     resources:
       requests:
         memory: "2Gi"
         cpu: "1000m"
       limits:
         memory: "3Gi"
         cpu: "2000m"
     affinity:
       nodeAffinity:
         preferredDuringSchedulingIgnoredDuringExecution:
           - weight: 100
             preference:
               matchExpressions:
                 - key: node-role.kubernetes.io/worker-airflow
                   operator: In
                   values:
                     - "true"
       podAntiAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           - labelSelector:
               matchExpressions:
                 - key: component
                   operator: In
                   values:
                     - api-server
             topologyKey: "kubernetes.io/hostname"
     env:
     ## this should achieve the same as the community chart's 
`airflow.extraPipPackages`. Note: underscore is necessary, not a typo!
       - name: _PIP_ADDITIONAL_REQUIREMENTS
         value: "airflow-exporter==1.6.0"
     service:
       type: NodePort
       ports:
         - name: api-server
           port: "{{ .Values.ports.apiServer }}"
           nodePort: 30010
   ## Uncomment below to enable Okta
   ## note: does not work when port-forwarding
     apiServerConfig: |
       import os
       from flask_appbuilder.security.manager import AUTH_OAUTH
   
       AUTH_TYPE = AUTH_OAUTH
   
       # registration configs
       AUTH_USER_REGISTRATION = True  # allow users who are not already in the 
FAB DB
       AUTH_USER_REGISTRATION_ROLE = "Viewer"  # this role will be given in 
addition to any AUTH_ROLES_MAPPING
   
       # the list of providers which the user can choose from
       OAUTH_PROVIDERS = [
         {
             "name": "okta",
             "icon": "fa-circle-o",
             "token_key": "access_token",
             "remote_app": {
                 "client_id": os.environ["OKTA_CLIENT_ID"],
                 "client_secret": os.environ["OKTA_CLIENT_SECRET"],
                 "api_base_url": "redacted",
                 "client_kwargs": {"scope": "openid profile email groups"},
                 "server_metadata_url": "redacted",
                 "access_token_url": "redacted",
                 "authorize_url": "redacted",
             },
         },
       ]
   
       # a mapping from the values of `userinfo["role_keys"]` to a list of FAB 
roles
       AUTH_ROLES_MAPPING = {
           "Viewer": ["Viewer"],
           "redacted": ["Admin"],
       }
   
       # if we should replace ALL the user's roles each login, or only on 
registration
       AUTH_ROLES_SYNC_AT_LOGIN = True
   
       # force users to re-auth after 30min of inactivity (to keep roles in 
sync)
       PERMANENT_SESSION_LIFETIME = 1800
   
   ## this is a bit of a confusing section. workers section is technically for 
deploying CeleryExecutors which we don't use
   ## but extraVolumes/extraVolumeMounts of this section is used to append to 
pod manifest of launched pods by airflow
   ## As of chart 1.20.0, workers.resources is deprecated in favor of 
workers.kubernetes.resources
   workers:
     extraVolumes:
     - name: dags
       hostPath:
         path: redacted
         type: Directory
     extraVolumeMounts:
       - name: dags
         mountPath: /opt/airflow/dags
         readOnly: true
         subPath: dags-v3
     kubernetes:
       resources:
         requests:
           memory: "500Mi"
           cpu: "200m"
         limits:
           memory: "1Gi"
           cpu: "2000m"
   
   ```
   
   ### Docker Image customizations
   
   _No response_
   
   ### Anything else?
   
   _No response_
   
   ### Are you willing to submit PR?
   
   - [ ] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to