[Python] gunicorn.errors.HaltServer: <HaltServer 'App failed to load.' 4> in Google Cloud Run...

Discussão em 'Python' iniciado por Stack, Agosto 26, 2025.

  1. Stack

    Stack Membro Participativo

    I have deployed a Cloud Run Function and am frequently seeing this error:

    2025-08-26 13:08:18.052 PDT DEBUG: False
    2025-08-26 13:08:18.052 PDT Type of DEBUG: <class 'bool'>
    2025-08-26 13:08:18.052 PDT Connecting to Cloud SQL with UNIX socket
    2025-08-26 13:08:18.161 PDT Failed to find attribute 'app' in 'main'.
    2025-08-26 13:08:18.162 PDT [2025-08-26 20:08:18 +0000] [6] [INFO] Worker exiting (pid: 6)
    2025-08-26 13:08:18.546 PDT [2025-08-26 20:08:18 +0000] [1] [ERROR] Worker (pid:6) exited with code 4
    2025-08-26 13:08:18.550 PDT Traceback (most recent call last): File "/layers/google.python.pip/pip/lib/python3.13/site-packages/gunicorn/arbiter.py", line 223, in run handler()
    2025-08-26 13:08:18.550 PDT ~~~~~~~^^
    2025-08-26 13:08:18.550 PDT File "/layers/google.python.pip/pip/lib/python3.13/site-packages/gunicorn/arbiter.py", line 256, in handle_term
    2025-08-26 13:08:18.550 PDT raise StopIteration
    2025-08-26 13:08:18.550 PDT StopIteration
    2025-08-26 13:08:18.550 PDT During handling of the above exception, another exception occurred:
    2025-08-26 13:08:18.551 PDT Traceback (most recent call last): File "/layers/google.python.pip/pip/bin/gunicorn", line 7, in <module> sys.exit(run())


    The code runs fine locally, although I am connecting to CloudSQL in a different way when it's deployed vs locally (CloudSQL Python Connector vs UNIX Socket), but it's worked before without modification to that method.

    The first 3 lines are print statements from outside of my main function.

    How the beginning of my function looks:

    import base64
    import json
    import os
    from importlib.metadata import version
    from datetime import date, datetime, timedelta

    import pandas as pd
    from flask import Response
    import pg8000
    import sqlalchemy
    from dateutil import tz, parser
    from dateutil.relativedelta import relativedelta
    from google.cloud import bigquery
    from google.oauth2 import service_account
    from google.cloud.sql.connector import Connector, IPTypes
    from sqlalchemy.exc import SQLAlchemyError
    from cloudevents.http import CloudEvent
    import functions_framework

    DEBUG = os.environ.get('DEBUG', 'True').capitalize() == 'True'

    print("SQLAlchemy version: ", version('SQLAlchemy'))

    print("DEBUG: ", DEBUG)
    print("Type of DEBUG: ", type(DEBUG))

    if not DEBUG:
    # Connect using UNIX socket (preferred for Cloud Run)
    print("Connecting to Cloud SQL with UNIX socket")
    db_socket_dir = os.environ.get("DB_SOCKET_DIR", "/cloudsql")
    # Connect using Unix Socket
    pg_engine = sqlalchemy.create_engine(
    # Equivalent URL:
    # postgresql+pg8000://<db_user>:<db_pass>@/<db_name>
    # ?unix_sock=<socket_path>/<cloud_sql_instance_name>/.s.PGSQL.5432
    sqlalchemy.engine.url.URL.create(
    drivername="postgresql+pg8000",
    username=db_user,
    password=db_pass,
    database=db_name,
    query={
    "unix_sock": "{}/{}/.s.PGSQL.5432".format(
    db_socket_dir, # e.g. "/cloudsql"
    instance_connection_name) # i.e "<PROJECT-NAME>:<INSTANCE-REGION>:<INSTANCE-NAME>"
    }
    ),
    # Pool size is the maximum number of permanent connections to keep.
    pool_size=0,
    # Temporarily exceeds the set pool_size if no connections are available.
    max_overflow=1,
    echo=True
    )
    else:
    db_hostname = DB_HOSTNAME
    db_port = 5432
    print("Connecting to Cloud SQL using Cloud SQL Python Connector")
    # # For local testing only
    db_hostname = "123.45.678.90"
    db_port = 5432
    pg_engine = sqlalchemy.create_engine(
    # Equivalent URL:
    # postgresql+pg8000://<db_user>:<db_pass>@<db_host>:<db_port>/<db_name>
    sqlalchemy.engine.url.URL.create(
    drivername="postgresql+pg8000",
    username=db_user,
    password=db_pass,
    host=db_hostname,
    port=db_port,
    database=db_name
    ),
    # Pool size is the maximum number of permanent connections to keep.
    pool_size=1,
    # Temporarily exceeds the set pool_size if no connections are available.
    max_overflow=0,
    echo=True
    )

    @functions_framework.cloud_event
    def main(cloud_event: CloudEvent) -> None:
    """Triggered from a message on a Cloud Pub/Sub topic.
    Args:
    event (dict): Event payload.
    context (google.cloud.functions.Context): Metadata for the event.
    """
    start_time = datetime.now()
    print("event: ", cloud_event)
    if not DEBUG:
    pubsub_message = base64.b64decode(cloud_event.data["message"]["data"]).decode('utf-8')
    else:
    # For local testing only
    pubsub_message = base64.b64decode(cloud_event.data["message"]["data"]).decode('utf-8')
    print("pubsub_message:", pubsub_message)
    settings = json.loads(pubsub_message)
    print("settings:", settings)
    ...


    It is deployed as a cloud run function, so I don't have access to the container itself.

    Any direction on how to debug this or prevent this is appreciated

    Continue reading...

Compartilhe esta Página