DHDataHọc
TheoryLesson 4/84 min read+10 XP

Lập lịch và backfill

Bạn sẽ học được

  • Viết lịch chạy bằng cron và đọc đúng ý nghĩa.
  • Hiểu quan hệ giữa lịch chạy và khoảng dữ liệu.
  • Dùng catchup và max_active_runs đúng cách.
  • Chạy backfill an toàn.
  • Xử lý dữ liệu đến muộn.

Khái niệm cốt lõi

Lịch chạy trả lời hai câu hỏi khác nhau:

  1. Khi nào chạy? — biểu thức cron.
  2. Xử lý dữ liệu nào? — data interval.

Hai câu này không giống nhau. DAG chạy lúc 02:00 ngày 2/3 xử lý dữ liệu ngày 1/3.

Cron cơ bản

code
┌ phút (0-59)
│ ┌ giờ (0-23)
│ │ ┌ ngày trong tháng (1-31)
│ │ │ ┌ tháng (1-12)
│ │ │ │ ┌ ngày trong tuần (0-6, 0 = Chủ nhật)
│ │ │ │ │
* * * * *
Biểu thứcNghĩa
0 2 * * *02:00 mỗi ngày
0 2 * * 102:00 thứ Hai
0 */6 * * *Mỗi 6 giờ
30 1 1 * *01:30 ngày 1 mỗi tháng
0 2 * * 1-502:00 các ngày làm việc

Airflow còn hỗ trợ @daily, @hourly, @weekly, và timedelta cho lịch đều đặn.

Catchup

catchup=True khiến Airflow chạy bù mọi khoảng dữ liệu từ start_date đến hiện tại.

code
@dag(
    dag_id="daily_orders",
    schedule="0 2 * * *",
    start_date=datetime(2024, 1, 1),
    catchup=False,
)

Nếu start_date là 1/1/2024 và hôm nay là 1/3/2026, bật catchup sẽ tạo gần 800 lần chạy cùng lúc. Điều này thường không phải điều bạn muốn khi mới triển khai.

Chỉ bật catchup khi thật sự cần xử lý lại quá khứ và đã tính đến tải hệ thống.

Max active runs

code
max_active_runs=1

Giới hạn số lần chạy đồng thời của một DAG. Với pipeline ghi vào cùng một bảng, đặt 1 để tránh hai lần chạy tranh nhau.

max_active_tasks giới hạn số task song song trong một lần chạy.

Backfill

Chạy lại một khoảng thời gian:

code
airflow dags backfill daily_orders \
  --start-date 2026-03-01 \
  --end-date 2026-03-07

Ba điều cần kiểm tra trước khi backfill:

  1. Task có idempotent không? Nếu không, backfill sẽ tạo dữ liệu trùng.
  2. Hệ thống đích có chịu được tải không?
  3. Có phụ thuộc bên ngoài nào bị gọi lại (email, API tính tiền) không?

Backfill không phải "chạy lại cho đẹp". Nó ghi dữ liệu thật vào hệ thống thật.

Dữ liệu đến muộn

Nguồn có thể đến muộn vài giờ hoặc vài ngày. Ba cách xử lý:

CáchKhi nào dùng
Chạy lại ngày cũ khi dữ liệu đếnCó cảnh báo độ tươi
Cửa sổ chờ cố địnhNguồn trễ đều đặn
Xử lý theo lô lớn hơnDữ liệu trễ nhiều ngày

Với cách đầu, cần đảm bảo task idempotent và có cơ chế phát hiện dữ liệu đến muộn.

Múi giờ

Airflow lưu thời gian theo UTC. Nếu nghiệp vụ theo giờ Việt Nam, đặt timezone trong DAG hoặc quy đổi rõ ràng:

code
import pendulum

@dag(
    dag_id="daily_orders",
    schedule="0 2 * * *",
    start_date=pendulum.datetime(2026, 1, 1, tz="Asia/Ho_Chi_Minh"),
)

Không có múi giờ, một ngày nghiệp vụ có thể bị cắt sai mốc.

Lỗi thường gặp

  • Bật catchup mà không biết: hàng trăm lần chạy đồng thời.
  • Backfill trên task không idempotent: dữ liệu trùng.
  • Không giới hạn max_active_runs: tranh chấp ghi.
  • Dùng giờ local trong code: lệch múi giờ.
  • Cron hiểu sai ngày trong tuần: chạy sai ngày.
  • Không kiểm tra tải trước backfill: làm sập hệ thống nguồn.

Thực hành

  1. Viết cron cho 02:00 thứ Hai đến thứ Sáu.
  2. Xác định khoảng dữ liệu của lần chạy 1/4 lúc 02:00 với lịch hằng ngày.
  3. Đặt max_active_runs=1 và giải thích lý do.
  4. Chạy backfill ba ngày trên môi trường dev.
  5. Thiết kế cách xử lý dữ liệu đến muộn hai ngày.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
Hàng trăm run cùng lúccatchup=TrueĐặt False
Dữ liệu trùng sau backfillTask không idempotentSửa cách ghi
Hai run tranh nhauKhông giới hạnmax_active_runs=1
Lệch một ngàyMúi giờĐặt timezone
Nguồn quá tảiBackfill lớnChạy theo lô nhỏ

Tóm tắt

  • Lịch chạy và khoảng dữ liệu là hai khái niệm khác nhau.
  • catchup=True có thể tạo hàng trăm lần chạy.
  • Giới hạn max_active_runs khi ghi vào cùng đích.
  • Backfill chỉ an toàn khi task idempotent.
  • Đặt múi giờ rõ ràng cho nghiệp vụ địa phương.

Use ← → to move between lessons