【问题标题】:Cloud function working locally but crashing in GCP (Function execution took 12681 ms, finished with status: 'crash')云函数在本地工作,但在 GCP 中崩溃(函数执行耗时 12681 毫秒,完成状态为:'crash')
【发布时间】:2020-09-17 13:59:22
【问题描述】:

这是我的代码的超级缩写版本(我将在 cmets 中放置所有内容的链接)

import ...

...

def main(data, context):
    log_client = logging.Client()

    log_name = 'cloudfunctions.googleapis.com%2Fcloud-functions'

    res = Resource(type="cloud_function",
                   labels={
                       "function_name": "refresh_classes",
                       "region": os.environ.get("FUNC_REGION")
                   })
    logger = log_client.logger(log_name.format(os.environ.get("PROJECT_ID")))

    db = sqlalchemy.create_engine(
        sqlalchemy.engine.url.URL(
            drivername="mysql+pymysql",
            username=os.environ.get("DB_USER"),
            password=os.environ.get("DB_PASS"),
            host=os.environ.get("DB_HOST"),
            port=3306,
            database=PRIMARY_TABLE_NAME
        ),
        pool_size=5,
        max_overflow=2,
        pool_timeout=30,
        pool_recycle=1800
    )
    start_time = perf_counter()

    check_if_table_exists(db)

    for i in range(START_IDX, END_IDX):
        print(i)
        logger.log_text(f"Checking class with id {i}", resource=res, severity="INFO")

        ...

    logger.log_text(f"Total seconds elapsed: {perf_counter() - start_time}", resource=res, severity="INFO")


if __name__ == '__main__':
    main('data', 'context')

当我在本地运行上述云功能时,配置了我的 GOOGLE_APPLICATION_CREDENTIALS 并设置了本地 Cloud MySQL 代理,详细的云日志记录通过,并且该功能顺利完成,正如我所期望的那样:

但是,当我将整个事情部署到 GCP 并尝试通过控制台触发它(云消息传递触发器)时,我得到的只是日志记录:

实际文字

{
 insertId: "******"  
 labels: {
  execution_id: "******"   
 }
 logName: "projects/******/logs/cloudfunctions.googleapis.com%2Fcloud-functions"  
 receiveTimestamp: "2020-05-29T22:11:13.435688367Z"  
 resource: {
  labels: {
   function_name: "******"    
   project_id: "******"    
   region: "us-central1"    
  }
  type: "cloud_function"   
 }
 severity: "DEBUG"  
 textPayload: "Function execution started"  
 timestamp: "2020-05-29T22:11:03.069889708Z"  
 trace: "projects/******/traces/******"  
}

{
 insertId: "******"  
 labels: {
  execution_id: "******"   
 }
 logName: "projects/******/logs/cloudfunctions.googleapis.com%2Fcloud-functions"  
 receiveTimestamp: "2020-05-29T22:11:16.331311285Z"  
 resource: {
  labels: {
   function_name: "******"    
   project_id: "******"    
   region: "us-central1"    
  }
  type: "cloud_function"   
 }
 severity: "DEBUG"  
 textPayload: "Function execution took 12362 ms, finished with status: 'crash'"  
 timestamp: "2020-05-29T22:11:15.430033249Z"  
 trace: "projects/******/traces/******"  
}

*我真的不知道什么是敏感信息,什么不是,所以我只是给一些随机的东西加了星标

在我写这篇文章时,我意识到更多的日志记录会有所帮助,所以我在记录器设置、数据库设置和我运行的表检查之间插入了一个 Google 记录器。

该函数在 Google 记录器设置之前就崩溃了。

所以在这一点上,我不确定是什么破坏了我的功能,而且我不知道如何找出来,因为 Google Cloud 日志记录没有帮助。错误 json 有一个 trace 属性,看起来很有希望,因为此时我只需要一个 Python 堆栈跟踪,但我不知道是否有办法看到它。

我应该注意,我通过 GCP 的 Cloud Function 控制台配置了环境变量。

主要有两件事会有所帮助:

  1. 如何查看崩溃云函数的 python 堆栈跟踪
  2. 是什么,特定于我的应用程序,可能导致它出现这种崩溃行为

【问题讨论】:

  • 你能分享你的requirement.txt文件吗?你是如何部署函数的? (不含敏感信息)

标签: python google-cloud-platform google-cloud-functions google-cloud-sql google-cloud-logging


【解决方案1】:

所以我终于想通了,如果不是通过 Cloud Scheduler 触发您的云功能,而是通过 Test Function 手动运行该功能

GCP 将为您提供引发的异常。就我而言,我的 Cloud MySQL 连接失败了

Error: function terminated. Recommended action: inspect logs for termination reason. Details:
(pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on '**.***.**.***' (timed out)")
(Background on this error at: http://sqlalche.me/e/e3q8)

所以我只需要引入一个环境变量来在通过代理连接和unix sockets 之间切换,如下所示:

if os.environ.get("ENV") == "local":
    db = sqlalchemy.create_engine(
        sqlalchemy.engine.url.URL(
            drivername="mysql+pymysql",
            username=os.environ.get("DB_USER"),
            password=os.environ.get("DB_PASS"),
            host=os.environ.get("DB_HOST"),
            port=3306,
            database=PRIMARY_TABLE_NAME
        ),
        pool_size=5,
        max_overflow=2,
        pool_timeout=30,
        pool_recycle=1800
    )
else:
    db = sqlalchemy.create_engine(
        sqlalchemy.engine.url.URL(
            drivername="mysql+pymysql",
            username=os.environ.get("DB_USER"),
            password=os.environ.get("DB_PASS"),
            database=PRIMARY_TABLE_NAME,
            query={"unix_socket": "/cloudsql/{}".format(os.environ.get("CLOUD_SQL_CONNECTION_NAME"))}
        ),
        pool_size=5,
        max_overflow=2,
        pool_timeout=30,
        pool_recycle=1800
    )

【讨论】:

    猜你喜欢
    • 2020-09-13
    • 2020-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-31
    相关资源
    最近更新 更多