在每个时区每天凌晨 3:00 运行 celery 任务?姜戈

如何解决在每个时区每天凌晨 3:00 运行 celery 任务?姜戈

我需要每天凌晨 3:00 为多个时区运行一项任务,在应用中每个组织都有一个时区。

class Organization(models.Model):

    timezone = models.IntegerField(choices=((i,i) for i in range(-12,13)))

因此,如果两个组织的时区不同,则任务应在各自时区的凌晨 3:00 执行,即不同时间。

我怎样才能做到这一点?

解决方法

对此的一种解决方案是:

  1. 列出所有必要的时区(例如 Asia/Manila)及其相应的 UTC 偏移量(例如 +8.0)。这是 timezone names and their UTC offsets 的完整列表。
  2. 获取每个时区 03:00 AM 的 UTC 等效值
  3. 将 Celery 配置为基于 UTC,然后使用 celery beat 安排任务,这些任务将在每个时区的 03:00 AM 以 UTC 转换后运行

代码:

from dataclasses import dataclass
from datetime import datetime,time,timezone
from decimal import Decimal
import pytz  # If using > Python3.9,you can try using the built-in library zoneinfo

### Step 1: Collect all the UTC offsets for all timezones

utc_offsets = set()

for tz in pytz.all_timezones:
    # If needed,filter the timezones to only the ones that are necessary,skip those that are not needed.
    dt = datetime.now(pytz.timezone(tz))

    # Decimal was used instead of the built-in float for a more accurate precision
    dt_utc_offset_seconds = Decimal(dt.utcoffset().total_seconds())
    dt_utc_offset_minutes = dt_utc_offset_seconds / Decimal('60')
    dt_utc_offset_hours = dt_utc_offset_minutes / Decimal('60')
    utc_offsets.add(dt_utc_offset_hours)

### Step 2: Get the equivalent in UTC of each timezone's 03:00 AM

TASK_HOUR_TARGET = Decimal('3')
task_hour_per_tz = set()

for utc_offset in utc_offsets:
    if utc_offset == 0:
        task_hour_as_utc_offset = TASK_HOUR_TARGET

    elif utc_offset > 0:
        task_hour_as_utc_offset = TASK_HOUR_TARGET - utc_offset

        if task_hour_as_utc_offset < 0:
            task_hour_as_utc_offset = 24 - abs(task_hour_as_utc_offset)

    elif utc_offset < 0:
        task_hour_as_utc_offset = TASK_HOUR_TARGET + abs(utc_offset)

        if task_hour_as_utc_offset >= 24:
            task_hour_as_utc_offset = task_hour_as_utc_offset - 24

    task_hour_per_tz.add((utc_offset,task_hour_as_utc_offset))

### Step 3: Schedule the execution of celery for each converted 03:00 AM of each timezone

@dataclass
class crontab:
    # For the sake of testing,here is a mocked celery.schedules.crontab
    minute: int
    hour: int

# This assumes that celery_app.conf.timezone = "UTC"
beat_schedule = {
    f"{utc_offset}": {
        'task': 'task.func','schedule': crontab(
            minute=int((task_hour * Decimal('60')) % Decimal('60')),hour=int(task_hour),),'kwargs': {"utc_offset": utc_offset},# To let the task know for what timezone is the trigger for
    }
    for utc_offset,task_hour in sorted(task_hour_per_tz) # No need of the sort. It is just here so that when we print the dictionary,the order is by utc_offset.
}

for key in beat_schedule:
    print(key,beat_schedule[key])

输出:

-12 {'task': 'task.func','schedule': crontab(minute=0,hour=15),'kwargs': {'utc_offset': Decimal('-12')}}
-11 {'task': 'task.func',hour=14),'kwargs': {'utc_offset': Decimal('-11')}}
-10 {'task': 'task.func',hour=13),'kwargs': {'utc_offset': Decimal('-10')}}
-9.5 {'task': 'task.func','schedule': crontab(minute=30,hour=12),'kwargs': {'utc_offset': Decimal('-9.5')}}
-9 {'task': 'task.func','kwargs': {'utc_offset': Decimal('-9')}}
-8 {'task': 'task.func',hour=11),'kwargs': {'utc_offset': Decimal('-8')}}
-7 {'task': 'task.func',hour=10),'kwargs': {'utc_offset': Decimal('-7')}}
-6 {'task': 'task.func',hour=9),'kwargs': {'utc_offset': Decimal('-6')}}
-5 {'task': 'task.func',hour=8),'kwargs': {'utc_offset': Decimal('-5')}}
-4 {'task': 'task.func',hour=7),'kwargs': {'utc_offset': Decimal('-4')}}
-3 {'task': 'task.func',hour=6),'kwargs': {'utc_offset': Decimal('-3')}}
-2.5 {'task': 'task.func',hour=5),'kwargs': {'utc_offset': Decimal('-2.5')}}
-2 {'task': 'task.func','kwargs': {'utc_offset': Decimal('-2')}}
-1 {'task': 'task.func',hour=4),'kwargs': {'utc_offset': Decimal('-1')}}
0 {'task': 'task.func',hour=3),'kwargs': {'utc_offset': Decimal('0')}}
1 {'task': 'task.func',hour=2),'kwargs': {'utc_offset': Decimal('1')}}
2 {'task': 'task.func',hour=1),'kwargs': {'utc_offset': Decimal('2')}}
3 {'task': 'task.func',hour=0),'kwargs': {'utc_offset': Decimal('3')}}
4 {'task': 'task.func',hour=23),'kwargs': {'utc_offset': Decimal('4')}}
4.5 {'task': 'task.func',hour=22),'kwargs': {'utc_offset': Decimal('4.5')}}
5 {'task': 'task.func','kwargs': {'utc_offset': Decimal('5')}}
5.5 {'task': 'task.func',hour=21),'kwargs': {'utc_offset': Decimal('5.5')}}
5.75 {'task': 'task.func','schedule': crontab(minute=15,'kwargs': {'utc_offset': Decimal('5.75')}}
6 {'task': 'task.func','kwargs': {'utc_offset': Decimal('6')}}
6.5 {'task': 'task.func',hour=20),'kwargs': {'utc_offset': Decimal('6.5')}}
7 {'task': 'task.func','kwargs': {'utc_offset': Decimal('7')}}
8 {'task': 'task.func',hour=19),'kwargs': {'utc_offset': Decimal('8')}}
8.75 {'task': 'task.func',hour=18),'kwargs': {'utc_offset': Decimal('8.75')}}
9 {'task': 'task.func','kwargs': {'utc_offset': Decimal('9')}}
9.5 {'task': 'task.func',hour=17),'kwargs': {'utc_offset': Decimal('9.5')}}
10 {'task': 'task.func','kwargs': {'utc_offset': Decimal('10')}}
10.5 {'task': 'task.func',hour=16),'kwargs': {'utc_offset': Decimal('10.5')}}
11 {'task': 'task.func','kwargs': {'utc_offset': Decimal('11')}}
12 {'task': 'task.func','kwargs': {'utc_offset': Decimal('12')}}
12.75 {'task': 'task.func','kwargs': {'utc_offset': Decimal('12.75')}}
13 {'task': 'task.func','kwargs': {'utc_offset': Decimal('13')}}
14 {'task': 'task.func','kwargs': {'utc_offset': Decimal('14')}}

从输出中可以看出,每个时区都有自己的计划任务,这些任务将在 UTC 的 03:00 AM(例如 UTC+8.0 的 19:00)运行。

  • 如果您不喜欢为每个时区生成单独的计划任务的想法,您可能需要配置一个更复杂的 crontab 例如crontab(minute=0,hour='0,1,2,3,4...') 但我认为某些时区组合不可能使用不同的分钟,例如以满足 UTC+5.0 和 UTC+5.5 转换后的 03:00 AM,即分别为 22:00 和 21:30(第 0 分钟和第 30 分钟)。虽然您也可能只是为不同的分钟设置生成不同的计划任务,例如第 0 分钟、第 15 分钟、第 30 分钟和第 45 分钟。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res