Files

5.7 KiB
Raw Permalink Blame History

美团券 ETL 定时任务 — 运维手册

对象:维护「美团 CPS 券抓取入库」这套定时任务的同事。 🔒 登录信息(服务器 IP / 账号密码 / DB 密码)见私密交接清单,不入库。 运行账号 cps 无 sudo,本手册所有操作都不需要 root。

它是什么

每小时全量抓美团 CPS 券(北京)→ upsert 进 PostgreSQL 的 meituan_coupon 表,作为 App「销量最高 / 智能推荐」两个 tab 的数据源。一轮约 140 秒、~2700 条;靠 cps 用户的 crontab 常驻,关终端也照跑。

代码 / 文件在哪(都在生产服务器上)

路径
代码目录 /opt/shaguabijia-app-server
抓取脚本 scripts/pull_meituan_coupons.py
Python(venv) /opt/shaguabijia-app-server/.venv/bin/python
配置(美团凭证 / DB 连接串) /opt/shaguabijia-app-server/.env(MT_CPS_* / DATABASE_URL)
日志 /home/cps/meituan_etl.log
运行锁 /tmp/meituan_etl.lock(根治版)或 ~/data/.meituan_etl.lock(过渡版,见文末)
定时配置 cps 用户 crontab(crontab -l)
入库表 PostgreSQL shaguabijia 库的 meituan_coupon

怎么看在不在跑 / 健康

crontab -l                      # 看定时任务(应有每小时第 17 分那条)
tail -n 20 ~/meituan_etl.log    # 看最近几轮:本轮完成 / 入库条数 / 有无报错
# 查库存量与新鲜度(走 .env 连接串,不用输 DB 密码):
cd /opt/shaguabijia-app-server && .venv/bin/python -c "from sqlalchemy import text; from app.db.session import engine; print(engine.connect().execute(text('select count(*) total, count(*) filter (where sale_volume_num is not null) sales, max(last_seen) last_run from meituan_coupon')).one())"

健康标准:last_run 在最近 12 小时内、total 两三千、日志最近一轮是 本轮完成(不是 Permission denied / Traceback)。

怎么启动

定时任务已在 cps 的 crontab 里常驻,随系统 cron 服务自动运行,无需手动启动。若 crontab 被清空、要重新装回:crontab -e,粘下面这行存盘。

# 根治版(锁文件已改到 /tmp 后用这条,推荐):
17 * * * * cd /opt/shaguabijia-app-server && .venv/bin/python -m scripts.pull_meituan_coupons --once --prune-hours 24 >> /home/cps/meituan_etl.log 2>&1

手动立即跑一轮(不等下一个整点,比如刚发现库空):

cd /opt/shaguabijia-app-server && .venv/bin/python -m scripts.pull_meituan_coupons --once --prune-hours 24

前台跑、约 140 秒,出现 本轮完成 即成功。

怎么关闭(停用定时任务)

crontab -e

在那一行最前面加 # 注释掉(推荐,保留备查),存盘即停;要彻底删就删那一行。

⚠️ 别用 crontab -r——它会清空你所有 cron,不只这一条。

怎么终止(杀掉正在跑的那一轮)

pgrep -af pull_meituan_coupons     # 查在跑的进程和 PID
pkill -f pull_meituan_coupons      # 杀掉它(或 kill <PID>)
rm -f /tmp/meituan_etl.lock ~/data/.meituan_etl.lock   # 清掉残留锁,否则下一轮可能"跳过本轮"

脚本有 30 分钟陈旧锁自动接管机制:即使没手动清锁,30 分钟后下一轮也会自愈;急着立刻重跑才需手动 rm 锁。

调整频率

crontab -e 改那行最前面的 cron 表达式:

频率 表达式
每小时第 17 分(当前) 17 * * * *
每 30 分钟 */30 * * * *
每 2 小时 17 */2 * * *

⚠️ 别调太密:一轮 ~140 秒,且要守美团限流(脚本已配速到 ~2–3 req/s,远低于 ~15 req/s 红线;402 内置退避重试)。每小时一轮足够,勿并行、勿调小页间 sleep。

脚本参数

  • --once:跑一轮(定时任务用这个)
  • --loop --interval 600:常驻循环,每 600 秒一轮(调试用)
  • --prune-hours N:清理超过 N 小时没再出现的旧券(默认 24;0=不清)
  • 锁文件位置可用环境变量 MEITUAN_ETL_LOCK=/path/to.lock 覆盖

详见脚本头部注释:head -30 scripts/pull_meituan_coupons.py

已知问题与根治(运行锁权限)

  • 现象:cron 报 PermissionError: [Errno 13] ... 'data/.meituan_etl.lock',每轮抓不进数据、表为空。
  • 根因:旧版脚本把运行锁建在代码目录的 data/ 下,而 data/ 属 root、cps 不可写(交接清单里"已给写权限"实际不成立)。
  • 根治(已在代码层修复):脚本把锁默认改到 /tmp/meituan_etl.lock(任何账号可写),并支持 MEITUAN_ETL_LOCK 覆盖。部署该版本后,用上面「根治版」那条干净 crontab 即可。
  • 过渡写法(根治版部署前的临时方案):crontab 里 cd /home/cps 把锁落到家目录、再用 PYTHONPATH 让代码仍能 import:
    17 * * * * cd /home/cps && PYTHONPATH=/opt/shaguabijia-app-server /opt/shaguabijia-app-server/.venv/bin/python -m scripts.pull_meituan_coupons --once --prune-hours 24 >> /home/cps/meituan_etl.log 2>&1
    
    根治版上线后,把这条换回上面的「根治版」标准写法即可。

注意事项

  • 只抓北京:脚本里 city_id 硬编码,扩城市需改脚本。
  • 表行数 > 单轮抓取数属正常:美团 product_view_sign 会轮换,跨轮累积;查询侧有 DISTINCT ON(dedup_key) 按「品牌|名|价」去重,用户看到的不重复;旧券 24h 后被 prune 清掉。
  • 别和 systemd 双跑:仓库 deploy/meituan-etl.{service,timer}未来由 root 纳入 systemd 正规部署的备选,和本 user cron 二选一、别同时开(否则重复抓、浪费限流额度)。当前生产用 user cron。
  • 改脚本 / 改部署:走 git + PR,让有 root 的人 /opt/deploy.sh 部署(git reset + alembic upgrade + 重启);cps 账号改不了 /opt 下的代码。