【问题标题】:Azure function does not execute other Python functionsAzure 函数不执行其他 Python 函数
【发布时间】:2021-05-12 22:45:22
【问题描述】:

我在main.py 中有以下代码,这是我项目的简化版本,我在其中检索一些数据、清理数据并将其导出到 Azure 中的 SQL 数据库。

问题是,当我使用 Azure 函数在本地运行它时,一切正常,我可以在终端中看到日志记录。

但是当我用azure start --verbose 运行它时,函数可以正确启动,但是执行我的函数export_data 不起作用。

简化代码

# import packages
# load_dotenv()

def get_data():
    # function which retrieves data


def export_data():
    # function which exports data and uses environment variables


def main(timer: func.TimerRequest) -> None:
    utc_timestamp = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc).isoformat()

    if timer.past_due:
        logging.info('The timer is past due! Writing data to database')
        export_data()

    logging.info('Python timer trigger function ran at %s', utc_timestamp)


if __name__ == "__main__":
    export_data()

我的代码

import os
import datetime
import logging
import pandas as pd
from sqlalchemy import create_engine
from dotenv import load_dotenv
import azure.functions as func
load_dotenv()


logging.basicConfig(
    format="%(asctime)s.%(msecs)03d [%(levelname)-5s] [%(name)s] - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
    level=logging.INFO,
)


def get_data():
    # get data
    logging.info("retrieving data")
    url = "https://data.rivm.nl/covid-19/COVID-19_aantallen_gemeente_per_dag.csv"
    df = pd.read_csv(url, sep=";")

    return df


def export_data():
    # export data
    df = get_data()

    uid = os.environ.get("username")
    password = os.environ.get("pw")
    server = '***.database.windows.net'
    database = os.environ.get("database")
    driver = "ODBC Driver 17 for SQL Server"

    connection_string = (
        f"mssql+pyodbc://{uid}:{password}@" f"{server}:1433/{database}?driver={driver}"
    )

    engine = create_engine(connection_string)
    con = engine.connect()

    logging.info("exporting data")
    df.head(10).to_sql('covid_19', con=con, if_exists='replace')


def main(timer: func.TimerRequest) -> None:
    utc_timestamp = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc).isoformat()

    if timer.past_due:
        logging.info('The timer is past due! Writing data to database')
        export_data()

    logging.info('Python timer trigger function ran at %s', utc_timestamp)


if __name__ == "__main__":
    export_data()

function.json

{
  "scriptFile": "main.py",
  "bindings": [
    {
      "name": "timer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */5 * * * *"
    }
  ]
}

编辑

所以这是日志的一部分,它显示了当我最初使用 func start --verbose 调用函数时函数运行的情况。注意时间,它不会在整个 5 分钟内发生,因为我的日程安排是基于此 ("schedule": "0 */5 * * * *"):

[2020-10-23T09:23:43.339] The timer is past due! Writing data to database
[2020-10-23T09:23:43.340] retrieving data
[2020-10-23T09:23:45.323] exporting data
[2020-10-23T09:23:46.182] Python timer trigger function ran at 2020-10-23T09:23:43.332697+00:00

那么在这部分之后,函数会根据定时器触发运行,但是什么也没有发生:

[2020-10-23T09:25:00.009] Executing 'Functions.zyppcovid' (Reason='Timer fired at 2020-10-23T11:25:00.0076610+02:00', Id=***)
[2020-10-23T09:25:00.012] Received FunctionInvocationRequest, request ID: ***, function ID: ***, invocation ID: ***
[2020-10-23T09:25:00.013] Function is sync, request ID: ***,function ID: ***, invocation ID: ***
[2020-10-23T09:25:00.013] Python timer trigger function ran at 2020-10-23T09:25:00.012563+00:00
[2020-10-23T09:25:00.013] Successfully processed FunctionInvocationRequest, request ID: ***, function ID: ***, invocation ID: ***
[2020-10-23T09:25:00.014] Executed 'Functions.zyppcovid' (Succeeded, Id=***, Duration=6ms)

【问题讨论】:

    标签: python azure azure-functions


    【解决方案1】:

    代码已经有一个定时器触发的主函数def main(timer: func.TimerRequest) -> None:。所以它不能做另一个主要的if __name__ == "__main__":。我这边测试一下,如果我只是用main创建一个简单的python代码,它可以在main函数成功下做export_data()

    【讨论】:

    • 奇怪的是,当我执行func start --verbose 时,它最初会运行该函数并执行导出,但是当它每 5 分钟触发一次计时器时,它不会执行导出。顺便说一句,我删除了if __name__ == __main__
    • 嗨@Zal 你提到export_data() 没有被执行。您的代码中有两个export_data(),您指的是哪一个? if timer.past_due: 下的那个还是if __name__ == "__main__": 下的那个?
    • 查看我的第一条评论:“顺便说一句,我删除了 if name == main”。我只使用这一行在没有 Azure Function 的情况下对其进行了测试,以查看导出是否有效。所以你可以忽略它。我将在我的 OP 中发布部分日志。
    • @Zal if timer.past_due: 下的代码只会在当前函数调用晚于预定时间时执行。可以参考这个document
    • 我明白了,但是请在我的原始帖子中查看我的日志,为什么它只在启动时触发,但之后它仍然每 5 分钟运行一次,但我的 export_data 没有。你的意思是我必须删除if timer.past_due:
    【解决方案2】:

    您应该将 export_data() 从 if 语句中取出。 if 语句只有在计时器过期时才会执行。

    您很可能希望在每次运行 azure 函数时都执行 export_date()。

    试试这个(注意用户定义的函数不再在 if 条件语句中,现在应该在函数运行时运行,而不仅仅是在计时器过期时):

    import os
    import datetime
    import logging
    import pandas as pd
    from sqlalchemy import create_engine
    from dotenv import load_dotenv
    import azure.functions as func
    load_dotenv()
    
    
    logging.basicConfig(
        format="%(asctime)s.%(msecs)03d [%(levelname)-5s] [%(name)s] - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
        level=logging.INFO,
    )
    
    
    def get_data():
        # get data
        logging.info("retrieving data")
        url = "https://data.rivm.nl/covid-19/COVID-19_aantallen_gemeente_per_dag.csv"
        df = pd.read_csv(url, sep=";")
    
        return df
    
    
    def export_data():
        # export data
        df = get_data()
    
        uid = os.environ.get("username")
        password = os.environ.get("pw")
        server = '***.database.windows.net'
        database = os.environ.get("database")
        driver = "ODBC Driver 17 for SQL Server"
    
        connection_string = (
            f"mssql+pyodbc://{uid}:{password}@" f"{server}:1433/{database}?driver={driver}"
        )
    
        engine = create_engine(connection_string)
        con = engine.connect()
    
        logging.info("exporting data")
        df.head(10).to_sql('covid_19', con=con, if_exists='replace')
    
    
    def main(timer: func.TimerRequest) -> None:
        utc_timestamp = datetime.datetime.utcnow().replace(
            tzinfo=datetime.timezone.utc).isoformat()
        
        logging.info('Writing data to database')
        export_data()
        logging.info('Writing data to database complete')
    
        if timer.past_due:
            logging.info('The timer is past due!')
            
    
        logging.info('Python timer trigger function ran at %s', utc_timestamp)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-01
      • 2019-11-25
      • 2016-05-27
      • 2020-09-08
      • 2013-06-17
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      相关资源
      最近更新 更多