You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Timer Function部署后无法上传文件至Blob存储报错求助

问题背景
  • 基于5分钟周期Timer Trigger开发的Azure Function,预期实现定时向Blob存储上传目标文件的能力
  • 代码在本地环境可正常完成文件下载、上传全流程,部署到Azure云端后执行失败

业务代码

主方法

device_client = IoTHubDeviceClient.create_from_connection_string(CONNECTION_STRING)
PATH_TO_FILE = wget.download("link-of-something", out=os.getcwd()) 
device_client.connect()
blob_name = os.path.basename(PATH_TO_FILE)
storage_info = device_client.get_storage_info_for_blob(blob_name)
store_blob(storage_info, PATH_TO_FILE)
device_client.shutdown()

辅助上传方法

def store_blob(blob_info, file_name):
    try:
        sas_url = "https://{}/{}/{}{}".format(
            blob_info["hostName"],
            blob_info["containerName"],
            blob_info["blobName"],
            blob_info["sasToken"]
        )

        print("\nUploading file: {} to Azure Storage as blob: {} in container {}\n".format(file_name, blob_info["blobName"], blob_info["containerName"]))

        # 上传指定文件
        with BlobClient.from_blob_url(sas_url) as blob_client:
            with open(file_name, "rb") as f:
                result = blob_client.upload_blob(f, overwrite=True)
                return (True, result)

    except FileNotFoundError as ex:
        # 捕获文件未找到异常,添加HTTP状态码用于向IoT Hub返回通知
        ex.status_code = 404
        return (False, ex)

    except AzureError as ex:
        # 捕获上传操作可能引发的Azure相关错误
        return (False, ex)

错误信息

精简后的错误堆栈如下:

Result: Failure Exception: OSError: [Errno 30] Read-only file system: './nasa_graphics_manual_nhb_1430-2_jan_1976.pdfjo243l48.tmp' Stack: File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 407, in _handle__invocation_request call_result = await self._loop.run_in_executor( File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 649, in _run_sync_func return ExtensionManager.get_sync_invocation_wrapper(context, File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/extension.py", line 215, in _raw_invocation_wrapper result = function(**args) File "/home/site/wwwroot/azure-function-timer/__init__.py", line 134, in main PATH_TO_FILE = wget.download("https://www.nasa.gov/sites/default/files/atoms/files/nasa_graphics_manual_nhb_1430-2_jan_1976.pdf", out=os.getcwd()) # wget to get the filename and path File "/home/site/wwwroot/.python_packages/lib/site-packages/wget.py", line 506, in download (fd, tmpfile) = tempfile.mkstemp(".tmp", prefix=prefix, dir=".") File "/usr/local/lib/python3.9/tempfile.py", line 336, in mkstemp return _mkstemp_inner(dir, prefix, suffix, flags, output_type) File "/usr/local/lib/python3.9/tempfile.py", line 255, in _mkstemp_inner fd = _os.open(file, flags, 0o600)

错误定位:异常触发点为wget.download方法调用行,根因是尝试在当前工作目录创建临时文件时触发只读文件系统错误。

根因分析

Azure Function Linux运行环境默认对应用根目录(即os.getcwd()返回的/home/site/wwwroot路径)做只读挂载,只有系统临时目录/tmp具备写入权限。
本地运行时工作目录可写,因此wget创建临时文件、下载文件的流程可以正常执行;部署到云端后,wget尝试在只读的工作目录下生成下载用的.tmp临时文件,直接触发[Errno 30] Read-only file system错误。

修复方案
  1. 修改wget下载的输出路径,从原来的os.getcwd()替换为系统临时目录,建议使用Python标准库tempfile的gettempdir()方法跨环境获取临时目录路径,兼容本地和云端运行场景:
    import tempfile
    # 替换原来的PATH_TO_FILE赋值逻辑
    PATH_TO_FILE = wget.download("目标文件下载链接", out=tempfile.gettempdir())
    
  2. 该方案完全适配当前业务场景:/tmp目录用于存放临时文件,文件不会持久化保留,函数执行完成后平台会自动回收空间,刚好满足下载后即时上传到Blob、不需要本地留存文件的需求,不需要额外调整Function配置。
  3. 如果后续有持久化写入文件的需求,可以在Function应用设置中添加配置项WEBSITES_ENABLE_APP_SERVICE_STORAGE = true开启应用目录写入权限,但对于当前临时下载的场景,直接使用/tmp目录是性能最优、改动最小的方案。

内容的提问来源于stack exchange,提问作者Merrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 12:57:21