求助:Azure函数部署至基础应用计划时出现文件找不到错误(消耗计划正常)
我运行一个Azure函数应用,部署在**消耗计划(Consumption-based Plan)时一切正常,但将完全相同的函数部署至基础应用计划(Basic App Plan)**时,出现如下错误:
[Conversion Error]: could not find file '/tmp/dbfs/ncreprov.dbf'
以下是实现功能的代码片段:
def run() -> bool: try: # 创建原始CSV的内存存储 raw_csv = BytesIO() # 从数据湖下载CSV到内存 DATA_LAKE.download_file( LAKE_CONTAINER, LAKE_SOURCE_DIRECTORY, CSV_FILENAME, hotload=True ).readinto(raw_csv) # 将字节流转换为字符串流 csv_file = StringIO(raw_csv.getvalue().decode(LAKE_CSV_ENCODING)) # 将字符串流转换为Pandas DataFrame csv_df = pd.read_csv(csv_file) # 移除DataFrame中的指定列 csv_df.drop(columns=EXCLUDED_COLUMNS, inplace=True) # 移除REDACTED字段为空的行 csv_df.dropna(subset=["REDACTED"]) # 连接SQL Server数据库 session, engine, metadata = SQLServerConnector( user=CLIENT_KEY_VAULT.mssql_user, password=CLIENT_KEY_VAULT.mssql_password, host=CLIENT_KEY_VAULT.mssql_host, database=CLIENT_KEY_VAULT.mssql_db ).connect() # 获取目标表的当前列 columns_response = session.execute( "SELECT column_name " "FROM REDACTED_TABLE " "WHERE table_name = 'REDACTED_TABLE_2'" ).fetchall() columns = [result[0] for result in columns_response] # 移除目标表中不存在的列 csv_df = csv_df[columns] # 清空目标表并写入数据 with session.begin(): session.execute("TRUNCATE TABLE REDACTED_TABLE_3") csv_df.to_sql( "REDACTED_TABLE_3", con=session, if_exists="append", index=False ) session.close() # 将处理后的DataFrame转回CSV transformed_csv = csv_df.to_csv(index=False) # 编码为字节 byte_csv = transformed_csv.encode(LAKE_CSV_ENCODING) # 放入字节流 final_csv = BytesIO(byte_csv) # 上传到数据湖的目标目录 DATA_LAKE.upload_file_to( LAKE_CONTAINER, LAKE_DESTINATION_DIRECTORY, stream=final_csv, file_name=CSV_FILENAME ) return True except Exception as exception: logging.error(f"[Error]: {exception}") return False
核心原因
错误提示的DBF文件并未在你的代码中直接操作,问题根源是Pandas或底层SQLAlchemy在执行to_sql时,因基础应用计划与消耗计划的环境差异,触发了临时文件的生成/读取逻辑:
- 消耗计划的沙箱环境限制磁盘操作,强制Pandas使用纯内存模式处理数据插入;
- 基础应用计划允许磁盘读写,但
/tmp目录的权限、路径映射存在问题,或是依赖库(如pyodbc)在该环境下存在遗留逻辑,尝试读取不存在的DBF文件。
具体解决步骤
强制
to_sql使用内存模式
Pandas的to_sql默认会在数据量较大时生成临时文件批量插入,可通过参数强制改为内存批量操作:csv_df.to_sql( "REDACTED_TABLE_3", con=session, if_exists="append", index=False, method='multi' # 强制内存批量插入 )也可配置SQLAlchemy引擎启用
fast_executemany,提升效率同时避免临时文件:# 修改SQLServerConnector的connect方法,创建引擎时添加参数 engine = create_engine( f"mssql+pyodbc://{user}:{password}@{host}/{database}?driver=ODBC+Driver+17+for+SQL+Server", fast_executemany=True )验证基础计划的临时目录权限
基础应用计划的/tmp目录理论上可读写,但部分环境可能存在路径映射问题,可添加代码检测:import os logging.info(f"/tmp目录存在: {os.path.exists('/tmp')}") logging.info(f"/tmp目录可写: {os.access('/tmp', os.W_OK)}")若权限异常,可改用Azure函数的默认临时目录(通过
os.environ['TEMP']获取),并确保依赖库能识别该路径。统一依赖库版本
两个计划的依赖库版本可能不一致(如Pandas、pyodbc、SQLAlchemy),导致行为差异。生成明确版本的requirements.txt,强制部署时使用指定版本,避免自动升级引发的兼容性问题。排查
hotload参数的影响DATA_LAKE.download_file的hotload=True可能触发底层临时文件逻辑,尝试改为False使用常规下载模式,看是否能消除错误。
内容的提问来源于stack exchange,提问作者holyshilo111

