如何正确处理Apache Airflow中的夏令时?

时间:2017-04-27 15:56:13

标签: dst airflow

在气流中,一切都应该是UTC(不受DST影响)。

但是,我们的工作流程基于受DST影响的时区提供服务。

示例场景:

  • 我们安排了一份工作,开始日期为东部时间上午8:00,时间间隔为24小时。
  • 每天上午8点东部时,调度程序会发现自上次运行以来已经过了24小时,并且正在运行该作业。
  • DST发生了,我们失去了一个小时。
  • 今天上午8点东部,调度员看到它只有23个小时,因为机器上的时间是UTC,并且直到东部时间上午9点才开始工作,这是一个延迟交付

有没有办法安排dags,以便它们在时间变化后的正确时间运行?

4 个答案:

答案 0 :(得分:5)

脱离我的头顶:

如果您的计算机具有时区感知功能,请将DAG设置为以UTC时间上午8点上午8点(UTC)运行。像0 11,12 * * *这样的东西。让第一个任务成为ShortCircuit操作员。然后使用像pytz这样的东西来定位当前时间。如果它在您所需的时间内,请继续(IE:运行DAG)。否则,返回False。您每天只需要额外的2个额外任务,但只要您的计算机没有超载,延迟就应该是最小的。

草率的例子:

from datetime import datetime
from pytz import utc, timezone

# ...

def is8AM(**kwargs):
    ti = kwargs["ti"]
    curtime = utc.localize(datetime.utcnow())
    # If you want to use the exec date:
    # curtime = utc.localize(ti.execution_date)
    eastern = timezone('US/Eastern') # From docs, check your local names
    loc_dt = curtime.astimezone(eastern)
    if loc_dt.hour == 8:
        return True
    return False

start_task = ShortCircuitOperator(
                task_id='check_for_8AM',
                python_callable=is8AM,
                provide_context=True,
                dag=dag
            )

希望这是有帮助的

编辑:运行时错误,减去而不是添加。此外,由于如何启动运行,如果您希望它们在8时运行,您最终可能希望按小时计划安排7AM。

答案 1 :(得分:3)

我们使用了@apathyman解决方案,但是我们只使用了PythonOperator而不是ShortCircuit,如果它不是我们想要的那个小时就会失败,并且使用timedelta重试1小时。 这样我们每天只运行1次而不是2次。

并且计划间隔设置为仅在第一个小时运行

基本上,类似的东西(大多数代码取自上面的答案,谢谢@apathyman):

from datetime import datetime
from datetime import timedelta
from pytz import utc, timezone


def is8AM(**kwargs):
    ti = kwargs["ti"]
    curtime = utc.localize(datetime.utcnow())
    # If you want to use the exec date:
    # curtime = utc.localize(ti.execution_date)
    eastern = timezone('US/Eastern') # From docs, check your local names
    loc_dt = curtime.astimezone(eastern)
    if loc_dt.hour == 8:
        return True
    exit("Not the time yet, wait 1 hour")

start_task = PythonOperator(
            task_id='check_for_8AM',
            python_callable=is8AM,
            provide_context=True,
            retries=1,
            retry_delay=timedelta(hours=1),
            dag=dag
        )

答案 2 :(得分:1)

我相信我们只需要一个PythonOperator来处理这种情况。

如果DAG需要在DST TZ中运行(例如:America / New_York,欧洲/伦敦,澳大利亚/悉尼),那么下面是我可以考虑的解决方法步骤:

  1. 将DAG计划转换为UTC TZ 因为TZ有DST,那么我们需要选择更大的偏移量 在做转换时。例如:
    • 使用America / New_York TZ:我们必须使用偏移量-4。因此,时间安排*/10 11-13 * * 1-5将转换为*/10 15-17 * * 1-5
    • 使用欧洲/伦敦:我们必须使用偏移量+1。因此,时间安排35 */4 * * *将转换为35 3-23/4 * * *
    • 澳大利亚/悉尼:我们必须使用偏移量+11。因此,时间安排15 8,9,12,18 * * *将转换为15 21,22,1,7 * * *
  2. 使用PythonOperator在所有主要任务之前完成任务。此任务将检查当前时间是否在指定TZ的DST中。如果是,则任务将在1小时内休眠。 这样我们就可以处理DST TZ的情况。

    def is_DST(zonename):
        tz = pytz.timezone(zonename)
        now = pytz.utc.localize(datetime.utcnow())
        return now.astimezone(tz).dst() != timedelta(0)
    
    
    def WQ_DST_handler(TZ, **kwargs):
        if is_DST(TZ):
            print('Currently is daily saving time (DST) in {0}, will process to next task now'.format(TZ))
        else:
            print('Currently is not daily saving time (DST) in {0}, will sleep 1 hour...'.format(TZ))
            time.sleep(60 * 60)
    
    
    DST_handler = PythonOperator(
        task_id='DST_handler',
        python_callable=WQ_DST_handler,
        op_kwargs={'TZ': TZ_of_dag},
        dag=dag
    )
    
    DST_handler >> main_tasks
    
  3. 这种解决方法有一个缺点:对于需要在DST TZ中运行的任何DAG,我们必须创建另外一个任务(上例中的DST_handler),并且此任务仍然需要发送到工作节点以执行(尽管它几乎只是一个睡眠命令。)

答案 3 :(得分:1)

当气流在1.8.x版上时被问到这个问题。

此功能自气流1.10起已内置。

https://airflow.apache.org/timezone.html

airflow.cfg中设置时区,应该正确处理dst。