我正在编写一个处理人员任务的小应用程序。非常简单,但就桌面设计而言,我所坚持的区域是一个重复性任务的情况,可以是一次性,每天,每周或每月。如果每周一次,那就是特定的一天,每周一次。每月是特定的一天。
我有一个任务表和一个recurring_type_id,并且会在代码中处理重复的任务,但这是理想的方法吗?另一种方法是在创建任务时插入所有任务 - 每个事件时间。但这似乎也不对。
任何人都可以就设计提出建议以及如何以可维护和有效的方式处理这个问题吗?
我正在使用SQL Server 2008 R2
答案 0 :(得分:12)
我会创建一个任务表来插入我的任务。
taskTable
|taskID |Freq |runAt |
-------------------------------
|1 |daily |1 |
|2 |daily |0 |
|3 |weekly |5 |
|4 |weekly |1 |
|5 |monthly|15 |
|6 |monthly|1 |
|7 |once |2013-7-4 |
日报的runAt从未被考虑过,因此输入的值无关紧要。
每周项的runAt是任务运行的星期几。
对于 mothly 的runAt是任务运行的月份的那一天(我通常在第一天运行的月末任务,因为它可以节省处理当月结束的那天的麻烦,尽管你可以用它来搞清楚lastDayOfMonth = datePart(d,dateadd(s,-1,dateadd(mm, datediff(m,0,getdate())+1,0)))
runAt for 一次是任务运行的实际日期。
然后我创建一个每天运行的任务,看看需要运行什么。
select taskID
from taskTable
where (freq = 'once' and runAt = convert(varchar(10),getDate(),21))
or freq = 'daily'
or (freq = 'weekly' and runAt = datePart(dw,getDate()))
or (freq = 'monthly' and runAt = datePart(d,getDate())
此查询为我提供了我需要运行的任何任务的所有taskID。
不确定这是否是您正在寻找的东西,但希望您能找到有用的东西。
答案 1 :(得分:5)
我会尝试使用经过试验和测试的解决方案。 Unix Cron Table解决方案。许多其他工具也使用此解决方案,如Hudson / Jenkins。
来自维基百科。
* * * * * command to be executed ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └───── day of week (0 - 7) (0 or 7 are Sunday, or use names) │ │ │ └────────── month (1 - 12) │ │ └─────────────── day of month (1 - 31) │ └──────────────────── hour (0 - 23) └───────────────────────── min (0 - 59)
它还允许条目的快捷方式名称。
Entry Description Equivalent To @yearly Run once a year at midnight in the morning of January 1 0 0 1 1 * @annually @monthly Run once a month at midnight in the morning of the first of the month 0 0 1 * * @weekly Run once a week at midnight in the morning of Sunday 0 0 * * 0 @daily Run once a day at midnight 0 0 * * * @hourly Run once an hour at the beginning of the hour 0 * * * *
从表格设计开始。
taskID cronExpression preDefinedDefinition 1 30 * * * * null 2 0 * * * * @hourly 3 ... ....
答案 2 :(得分:1)
我做了一件非常相似的事情:
_id
interval_type
time
day
next
day
字段表示区间内的日期,单次和每日为空。表中的next
字段用于标识下次运行任务的时间。当任务运行时设备关闭的情况下需要这样做。您只需要决定如何处理一个或多个错过的时间间隔。
答案 3 :(得分:1)
我应该像表格一样使用日期作为参考
taskid date_reference Freq distance
----------- -------------- --------------- -----------
1 2011-01-01 daily NULL
2 2011-01-17 monthly NULL
3 2013-01-17 weekly NULL
4 2013-01-24 once NULL
5 2011-01-01 monthly NULL
6 2011-01-01 monthly NULL
7 2011-01-01 before_eomonth 5
8 2013-01-01 loop_day 4
9 2013-01-01 loop_month 4
所以你可以通过多种方式检查这段时间......
传统的每周,每日,每月和一次。像长矛的解决方案..
但你会有几种不同的方式,比如
每4天
每4个月
或5月到月底
或月末
应考虑在任务循环结束时包含另一个日期......
但是,工作永远不会完成......所以,它永远不会被使用..;)
答案 4 :(得分:1)
我建议使用行业标准的iCalendar格式(http://www.rfc-editor.org/rfc/rfc5545.txt),而不是尝试为此设计关系设计。你可以看到一些例子here。由于您的重复模式看起来非常简单,因此为它们创建iCalendar表达式应该是一项非常简单的任务。
这是一个有用的语法验证器:http://severinghaus.org/projects/icv/
答案 5 :(得分:0)
目前尚不清楚您的环境究竟是什么,但开源Job Scheduler可以解决此类任务。
答案 6 :(得分:0)
我已经在这里给出了答案并提出了以下数据库结构:
Column Data Type
id int
task_name nvarchar(50)
frequency_type nvarchar(10)
runat_day int
runat_month int
runat_year int
数据如下所示:
id task_name frequency_type runat_day runat_month runat_year
1 Do this Once once 16 2 2018
2 Do this Monthly monthly 31 0 0
3 Do this Yearly yearly 28 2 0
4 Do this Daily daily 0 0 0
5 Do this Weekly weekly 6 0 0
将数据拉回的查询如下所示:
DECLARE @chosen_date datetime = '2018-02-28'
DECLARE @lastDayOfMonth int = datePart(d,dateadd(s,-1,dateadd(mm, datediff(m,0,getdate())+1,0)))
select task_name
from scheduled_tasks
where (frequency_type = 'once' and runat_day = DATEPART(DAY, @chosen_date) and runat_month = DATEPART(MONTH, @chosen_date) and runat_year = DATEPART(YEAR, @chosen_date))
or frequency_type = 'daily'
or (frequency_type = 'weekly' and runat_day = DATEPART(WEEKDAY,@chosen_date))
or (frequency_type = 'monthly' and runat_day = DATEPART(DAY, @chosen_date))
or (frequency_type = 'monthly' and @lastDayOfMonth = DATEPART(DAY, @chosen_date) and runat_day >= @lastDayOfMonth)
or (frequency_type = 'yearly' and runat_day = DATEPART(DAY, @chosen_date) and runat_month = DATEPART(MONTH, @chosen_date))
到目前为止,我的所有用例都已正确显示,即使是在某一天没有存在的某一天的月末日期也会得到正确处理(例如,每个月的第31个仍然会被触发) 2月28日)
给定frequency_type所不需要的字段只有零或空,并且被查询忽略。
它不会考虑在闰年2月29日发生的年度事件,也不会以任何方式考虑时间。
答案 7 :(得分:0)
我已经阅读了上面的答案,这是我认为应该做的:
计划
Id
类型(每日,每月,每周,固定,每年)-枚举
频率(可以是1-7 [一周中的天],1-30(或28)[一个月中的天],1-365 [一年中的天]或为null(对于每日,固定)-ArrayField (以整数为单位)-[1,7]或[23]或[235]或null
时间(UTC中的一天中的时间)-ArrayField(Char字符串-['9:00','13:30']
日期(用于固定类型)-datetime-2009-03-21
is_active(布尔值)-用于启用,禁用计划
名称(CharField)-如果要命名时间表
其余字段将需要您所构建的内容的上下文。
现在,为此,我正在考虑每30分钟运行一次cronjob(我花的时间输入间隔为30分钟),它运行一个脚本(在我的情况下为django管理命令),该脚本从该表中筛选出需要运行:
查询将是这样的:
current_day_of_week = 3
current_day_of_month = 24
current_day_of_year = 114
current_time = 13:30
current_date = 2019-04-24
Filter records that match the below query(not even psuedo code)(I'm using Q objects(https://docs.djangoproject.com/en/2.2/topics/db/queries/#complex-lookups-with-q-objects)
Q(daily AND current_time) OR
Q(weekly AND current_day_of_week AND current_time) OR
Q(monthly AND current_day_of_month AND current_time) OR
Q(yearly AND current_day_of_year AND current_time) OR
Q(fixed AND current_date AND current_time)