FunctionGraph 定时任务实战:每天凌晨自动清理 OBS 过期临时文件

举报
yd_274568041 发表于 2026/11/12 10:18:05 2026/11/12
【摘要】 用 FunctionGraph 定时触发器加 OBS SDK,搭建每天凌晨 2 点自动清理过期临时文件的 Serverless 定时任务:完整 Python 代码、打包步骤、Cron 表达式与 UTC 时区换算、IAM 委托配置,以及验证流程与避坑清单。

很多业务都会在对象存储里产生临时文件:图片处理中间结果、导出报表、上传分片残留、日志归档……如果不定期清理,桶会越长越大,既多花存储费用,列对象时也越来越慢。本文用华为云 FunctionGraph 加 OBS,实战搭建一个“每天凌晨 2 点自动清理过期临时文件”的定时任务:不用买服务器、不用常驻进程,全部用 Serverless 完成。

一、方案总览

链路很简单:TIMER 定时触发器 → FunctionGraph Python 函数 → OBS Python SDK 遍历并删除过期对象。

  • 触发器:FunctionGraph 自带的 TIMER 类型,按 Cron 表达式每天触发一次。
  • 函数:Python 3.9,入口 handler(event, context),只删除指定前缀(如 temp/)下超过保留天数的文件。
  • 权限:函数通过 IAM 委托访问 OBS,不在代码里写 AK/SK。
  • 成本:按执行次数和运行时长计费,凌晨跑一次清理通常只有几分钱量级,函数本身没有闲置费用。

为什么不用 OBS 生命周期规则?生命周期规则也能过期删除,但它是桶级别、按整个前缀生效的粗粒度策略;需要“只删 temp/ 下超过 7 天的文件、同时记录删除清单、失败时告警”这种精细逻辑时,函数更灵活。两者也可以叠加使用。

二、准备工作

  1. 开通 FunctionGraph 服务:进入华为云控制台,搜索 FunctionGraph,开通即可,无需预购资源。
  2. 准备 OBS 桶:确认桶名、所在区域,例如华北-北京四 cn-north-4;临时文件统一放在 temp/ 前缀下。
  3. 约定保留策略:本文示例保留 7 天,即删除最后修改时间超过 7 天的对象;保留天数、桶名、前缀全部用环境变量传入,方便不同环境复用。
  4. 准备 Python 环境:本地安装 Python 3.9,函数代码依赖 OBS Python SDK(esdk-obs-python)。

三、编写清理函数

核心逻辑是三步:分页列出对象、按最后修改时间判断是否过期、批量删除。

# cleanup_obs_temp.py
import os
import time
from obs import ObsClient

def handler(event, context):
    logger = context.getLogger()
    ak = os.environ.get("HUAWEI_AK")
    sk = os.environ.get("HUAWEI_SK")
    server = os.environ.get("OBS_ENDPOINT", "https://obs.cn-north-4.myhuaweicloud.com")
    bucket = os.environ.get("OBS_BUCKET")
    prefix = os.environ.get("OBS_PREFIX", "temp/")
    retain_days = int(os.environ.get("RETAIN_DAYS", "7"))

    client = ObsClient(access_key_id=ak, secret_access_key=sk, server=server)
    cutoff = time.time() - retain_days * 86400
    marker = ""
    deleted, scanned = 0, 0
    while True:
        resp = client.listObjects(bucket, prefix=prefix, marker=marker, max_keys=1000)
        for obj in resp.body.contents:
            scanned += 1
            if obj["lastModified"] < cutoff:
                client.deleteObject(bucket, obj["key"])
                deleted += 1
                logger.info("deleted: %s", obj["key"])
        if not resp.body.is_truncated:
            break
        marker = resp.body.next_marker
    logger.info("scanned %d, deleted %d", scanned, deleted)
    return {"scanned": scanned, "deleted": deleted}

几点说明:

  • 入口签名固定为 handler(event, context),event 是触发器传入的事件,TIMER 触发时内容为定时配置;context 提供日志等运行时上下文。
  • listObjects 单次最多返回 1000 个对象,必须用 marker 分页,否则大桶会漏删。
  • 删除前用 lastModified 判断是否过期,且只处理 temp/ 前缀,避免误删业务数据。
  • 配置全部走环境变量,不硬编码桶名和密钥。

四、打包与创建函数

FunctionGraph 的 Python 运行时不预装 esdk-obs-python,需要把 SDK 打进部署包:本地执行 pip install esdk-obs-python -t .,把 obs 包目录和 cleanup_obs_temp.py 放在同一层级打成 zip 上传。

控制台创建函数步骤:

  1. FunctionGraph 控制台 → 函数列表 → 创建函数 → 自定义创建。
  2. 运行时选 Python3.9,函数名 obs-temp-cleanup,入口写 cleanup_obs_temp.handler。
  3. 上传 zip 部署包;内存 128MB 起步,超时时间设为 60 秒(默认只有 3 秒,大桶清理一定会超时)。
  4. 在“环境变量”里配置 OBS_BUCKET、OBS_PREFIX=temp/、RETAIN_DAYS=7,以及 OBS_ENDPOINT。
  5. 保存后在控制台手动执行一次,看日志输出是否正常列出和删除文件。

五、创建定时触发器

  1. 进入函数详情 → 触发器 → 创建触发器,类型选 TIMER。
  2. 定时规则选 Cron 表达式。FunctionGraph 用 Quartz Cron,6 个字段:秒 分 时 日 月 周。每天凌晨 2 点(北京时间)对应的 UTC 时间是前一天 18:00,所以表达式是 0 0 18 * * ?。
  3. 触发器名称建议用 daily-2am-cleanup 这种“频率-时间-用途”格式,一眼能看出用途。
  4. 建议先用禁用状态创建触发器,手动验证函数无误后再启用。

时区是最容易踩的坑

FunctionGraph 的 TIMER 触发器默认使用 UTC 时间,不是北京时间。直接写 0 0 2 * * ?,实际是北京时间上午 10 点执行。换算关系:北京时间凌晨 2:00 等于 UTC 前一天 18:00;北京时间凌晨 0:00 等于 UTC 前一天 16:00;北京时间上午 8:00 等于 UTC 当天 0:00。

另外注意 Quartz 的 ? 规则:日(day-of-month)和周(day-of-week)不能同时为 *,其中一个必须用 ?。写 0 0 18 * * * 会报 InvalidParameter 错误,正确写法是 0 0 18 * * ?。

六、权限与安全

  • 优先用 IAM 委托:在函数详情 → 委托中配置,让函数以委托身份访问 OBS,代码和环境变量里都不出现 AK/SK。
  • 最小权限:委托只授予 OBS 桶的读写权限,不要给账号级通配权限;不同环境用不同委托。
  • 密钥轮换:如果暂时用 AK/SK 走环境变量,要定期轮换,并尽快迁移到委托方式。
  • 误删防护:生产桶先在测试桶验证;首次上线前把删除动作改成只记录日志的演练模式,确认清单无误后再真正删除。

七、验证流程

  1. 控制台查看触发器:函数详情 → 触发器,应看到 daily-2am-cleanup,状态为 ACTIVE。
  2. 手动测试:在控制台手动执行一次函数,日志应输出本次扫描和删除的数量。
  3. 等一天看自动执行:第二天凌晨 2 点后查看函数执行历史,确认被 TIMER 自动触发。
  4. OBS 侧确认:去 OBS 控制台看桶里 temp/ 前缀下超过 7 天的文件是否已被删除。

八、容易踩的坑清单

  • 超时时间太短:默认 3 秒基本不够用,设 60 秒;文件量巨大时调到 300 秒(最大 900 秒)或分批处理。
  • 忘记分页:单次列对象上限 1000,不分页会漏删。
  • 重复触发:TIMER 偶尔重复执行,删除操作本身是幂等的,删不存在的对象不会报错;但如果加了发通知等逻辑,要注意去重。
  • 冷启动:函数首次执行有几秒冷启动延迟,凌晨清理场景对延迟不敏感,可以忽略。
  • 静默失败:一定要记日志并配告警。在函数里用 context.getLogger().info() 记录每次清理的文件数和文件名,再在云监控 CES 上配一个告警,函数执行失败时通知你,否则定时任务静默失败可能很久才发现。

九、成本与扩展

函数按请求次数和执行时长计费,每天跑一次、每次几十秒的量级,成本很低;没有常驻服务器,也就没有闲置费用。跑通之后,还可以顺着这个模式扩展:把清理结果写到日志或发到消息通知;给多个桶配置多组触发器;或者把“定期巡检、报表生成、数据归档”这类轻量自动化都收敛到同一套定时任务框架里。

结尾

定时清理这件事本身不复杂,真正的价值在于“不用人惦记”:规则定好之后,临时文件每天凌晨自己消失,存储费用和运维负担都降下来。如果你也在用 OBS 存临时文件,不妨按上面的步骤花半小时搭一个,第二天早上看一眼执行日志,就能确认它已经开始工作了。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。