Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 492 lines (399 sloc) 19.207 kb
641e838 @ask Cosmetics
ask authored
1 # -*- coding: utf-8 -*-
27caaad @ask Adds module docstrings
ask authored
2 """
641e838 @ask Cosmetics
ask authored
3 celery.schedules
4 ~~~~~~~~~~~~~~~~
27caaad @ask Adds module docstrings
ask authored
5
641e838 @ask Cosmetics
ask authored
6 Schedules define the intervals at which periodic tasks
7 should run.
27caaad @ask Adds module docstrings
ask authored
8
6b52605 @ask Updates copyright years to include 2012
ask authored
9 :copyright: (c) 2009 - 2012 by Ask Solem.
641e838 @ask Cosmetics
ask authored
10 :license: BSD, see LICENSE for more details.
27caaad @ask Adds module docstrings
ask authored
11
641e838 @ask Cosmetics
ask authored
12 """
1dfe6d0 @ask Remove 2.4 workarounds
ask authored
13 from __future__ import absolute_import
14
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
15 import re
16
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
17 from datetime import datetime, timedelta
72dafab celery.schedules: Cosmetics
Ask Solem authored
18 from dateutil.relativedelta import relativedelta
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
19
c86a7df @ask The current datetime now taken from loader.now
ask authored
20 from . import current_app
b6179c7 @ask Use new-style relative imports
ask authored
21 from .utils import is_iterable
e569d22 @ask Celerybeat interval schedules were accidentally rounded
ask authored
22 from .utils.timeutils import (timedelta_seconds, weekday, maybe_timedelta,
b6179c7 @ask Use new-style relative imports
ask authored
23 remaining, humanize_seconds)
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
24 from .datastructures import AttributeDict
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
25
26
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
27 class ParseException(Exception):
28 """Raised by crontab_parser when the input can't be parsed."""
29
30
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
31 class schedule(object):
32 relative = False
33
c86a7df @ask The current datetime now taken from loader.now
ask authored
34 def __init__(self, run_every=None, relative=False, nowfun=None):
e569d22 @ask Celerybeat interval schedules were accidentally rounded
ask authored
35 self.run_every = maybe_timedelta(run_every)
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
36 self.relative = relative
4d83dec @ask Fixes reduce of schedule objects
ask authored
37 self.nowfun = nowfun
38
39 def now(self):
40 return (self.nowfun or current_app.now)()
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
41
42 def remaining_estimate(self, last_run_at):
43 """Returns when the periodic task should run next as a timedelta."""
c86a7df @ask The current datetime now taken from loader.now
ask authored
44 return remaining(last_run_at, self.run_every, relative=self.relative,
4d83dec @ask Fixes reduce of schedule objects
ask authored
45 now=self.now())
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
46
47 def is_due(self, last_run_at):
0afa1ef Docs: Replaced all occurences of ``literal`` with `literal`
Ask Solem authored
48 """Returns tuple of two items `(is_due, next_time_to_run)`,
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
49 where next time to run is in seconds.
50
8d85334 Improved docs
Ask Solem authored
51 e.g.
52
0afa1ef Docs: Replaced all occurences of ``literal`` with `literal`
Ask Solem authored
53 * `(True, 20)`, means the task should be run now, and the next
8d85334 Improved docs
Ask Solem authored
54 time to run is in 20 seconds.
55
0afa1ef Docs: Replaced all occurences of ``literal`` with `literal`
Ask Solem authored
56 * `(False, 12)`, means the task should be run in 12 seconds.
8d85334 Improved docs
Ask Solem authored
57
58 You can override this to decide the interval at runtime,
59 but keep in mind the value of :setting:`CELERYBEAT_MAX_LOOP_INTERVAL`,
60 which decides the maximum number of seconds celerybeat can sleep
61 between re-checking the periodic task intervals. So if you
62 dynamically change the next run at value, and the max interval is
63 set to 5 minutes, it will take 5 minutes for the change to take
64 effect, so you may consider lowering the value of
65 :setting:`CELERYBEAT_MAX_LOOP_INTERVAL` if responsiveness is of
66 importance to you.
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
67
4cd0a28 @ask Default for CELERYBEAT_MAX_LOOP_INTERVAL now set by individual scheduler...
ask authored
68 .. admonition:: Scheduler max interval variance
69
59a4227 @ask Doc improvements
ask authored
70 The default max loop interval may vary for different schedulers.
71 For the default scheduler the value is 5 minutes, but for e.g.
72 the django-celery database scheduler the value is 5 seconds.
4cd0a28 @ask Default for CELERYBEAT_MAX_LOOP_INTERVAL now set by individual scheduler...
ask authored
73
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
74 """
75 rem_delta = self.remaining_estimate(last_run_at)
76 rem = timedelta_seconds(rem_delta)
77 if rem == 0:
e569d22 @ask Celerybeat interval schedules were accidentally rounded
ask authored
78 return True, self.seconds
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
79 return False, rem
80
bd82037 @ask schedule: Added __repr__
ask authored
81 def __repr__(self):
e569d22 @ask Celerybeat interval schedules were accidentally rounded
ask authored
82 return "<freq: %s>" % self.human_seconds
bd82037 @ask schedule: Added __repr__
ask authored
83
289b1a5 New tests for the new celery.beat (92% coverage)
Ask Solem authored
84 def __eq__(self, other):
85 if isinstance(other, schedule):
86 return self.run_every == other.run_every
87 return self.run_every == other
88
e569d22 @ask Celerybeat interval schedules were accidentally rounded
ask authored
89 @property
90 def seconds(self):
91 return timedelta_seconds(self.run_every)
92
93 @property
94 def human_seconds(self):
95 return humanize_seconds(self.seconds)
96
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
97
98 class crontab_parser(object):
72dafab celery.schedules: Cosmetics
Ask Solem authored
99 """Parser for crontab expressions. Any expression of the form 'groups'
4fbdffd PEP8ify
Ask Solem authored
100 (see BNF grammar below) is accepted and expanded to a set of numbers.
72dafab celery.schedules: Cosmetics
Ask Solem authored
101 These numbers represent the units of time that the crontab needs to
102 run on::
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
103
104 digit :: '0'..'9'
105 dow :: 'a'..'z'
106 number :: digit+ | dow+
107 steps :: number
108 range :: number ( '-' number ) ?
109 numspec :: '*' | range
110 expr :: numspec ( '/' steps ) ?
111 groups :: expr ( ',' expr ) *
112
113 The parser is a general purpose one, useful for parsing hours, minutes and
114 day_of_week expressions. Example usage::
115
72dafab celery.schedules: Cosmetics
Ask Solem authored
116 >>> minutes = crontab_parser(60).parse("*/15")
117 [0, 15, 30, 45]
118 >>> hours = crontab_parser(24).parse("*/4")
119 [0, 4, 8, 12, 16, 20]
120 >>> day_of_week = crontab_parser(7).parse("*")
121 [0, 1, 2, 3, 4, 5, 6]
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
122
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
123 It can also parse day_of_month and month_of_year expressions if initialized
124 with an minimum of 1. Example usage::
125
126 >>> days_of_month = crontab_parser(31, 1).parse("*/3")
127 [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31]
128 >>> months_of_year = crontab_parser(12, 1).parse("*/2")
129 [1, 3, 5, 7, 9, 11]
130 >>> months_of_year = crontab_parser(12, 1).parse("2-12/2")
131 [2, 4, 6, 8, 10, 12]
132
133 The maximum possible expanded value returned is found by the formula::
134
135 max_ + min_ - 1
136
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
137 """
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
138 ParseException = ParseException
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
139
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
140 _range = r'(\w+?)-(\w+)'
141 _steps = r'/(\w+)?'
142 _star = r'\*'
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
143
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
144 def __init__(self, max_=60, min_=0):
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
145 self.max_ = max_
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
146 self.min_ = min_
9ba282f @ask Cosmetics
ask authored
147 self.pats = (
148 (re.compile(self._range + self._steps), self._range_steps),
149 (re.compile(self._range), self._expand_range),
150 (re.compile(self._star + self._steps), self._star_steps),
151 (re.compile('^' + self._star + '$'), self._expand_star))
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
152
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
153 def parse(self, spec):
154 acc = set()
155 for part in spec.split(','):
9ba282f @ask Cosmetics
ask authored
156 if not part:
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
157 raise self.ParseException("empty part")
9ba282f @ask Cosmetics
ask authored
158 acc |= set(self._parse_part(part))
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
159 return acc
160
161 def _parse_part(self, part):
162 for regex, handler in self.pats:
163 m = regex.match(part)
164 if m:
165 return handler(m.groups())
166 return self._expand_range((part, ))
167
168 def _expand_range(self, toks):
169 fr = self._expand_number(toks[0])
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
170 if len(toks) > 1:
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
171 to = self._expand_number(toks[1])
172 return range(fr, min(to + 1, self.max_ + 1))
9ba282f @ask Cosmetics
ask authored
173 return [fr]
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
174
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
175 def _range_steps(self, toks):
176 if len(toks) != 3 or not toks[2]:
177 raise self.ParseException("empty filter")
f4f8e3b @dhepper Changed crontab_parser match Vixie cron for ranges with steps, e.g. 1-59...
dhepper authored
178 return self._expand_range(toks[:2])[::int(toks[2])]
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
179
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
180 def _star_steps(self, toks):
181 if not toks or not toks[0]:
182 raise self.ParseException("empty filter")
f4f8e3b @dhepper Changed crontab_parser match Vixie cron for ranges with steps, e.g. 1-59...
dhepper authored
183 return self._expand_star()[::int(toks[0])]
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
184
9ba282f @ask Cosmetics
ask authored
185 def _expand_star(self, *args):
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
186 return range(self.min_, self.max_ + self.min_)
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
187
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
188 def _expand_number(self, s):
189 if isinstance(s, basestring) and s[0] == '-':
190 raise self.ParseException("negative numbers not supported")
191 try:
192 i = int(s)
193 except ValueError:
194 try:
195 i = weekday(s)
196 except KeyError:
197 raise ValueError("Invalid weekday literal '%s'." % s)
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
198
199 if i < self.min_:
200 raise ValueError("Invalid beginning range - %s < %s." %
201 (i, self.min_))
cd57928 @ask Rewrites the crontab parser using regexes, to remove the pyparsing depen...
ask authored
202 return i
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
203
204
205 class crontab(schedule):
0afa1ef Docs: Replaced all occurences of ``literal`` with `literal`
Ask Solem authored
206 """A crontab can be used as the `run_every` value of a
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
207 :class:`PeriodicTask` to add cron-like scheduling.
208
209 Like a :manpage:`cron` job, you can specify units of time of when
210 you would like the task to execute. It is a reasonably complete
211 implementation of cron's features, so it should provide a fair
212 degree of scheduling needs.
213
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
214 You can specify a minute, an hour, a day of the week, a day of the
215 month, and/or a month in the year in any of the following formats:
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
216
217 .. attribute:: minute
218
219 - A (list of) integers from 0-59 that represent the minutes of
220 an hour of when execution should occur; or
221 - A string representing a crontab pattern. This may get pretty
222 advanced, like `minute="*/15"` (for every quarter) or
223 `minute="1,13,30-45,50-59/2"`.
224
225 .. attribute:: hour
226
227 - A (list of) integers from 0-23 that represent the hours of
228 a day of when execution should occur; or
229 - A string representing a crontab pattern. This may get pretty
230 advanced, like `hour="*/3"` (for every three hours) or
231 `hour="0,8-17/2"` (at midnight, and every two hours during
232 office hours).
233
234 .. attribute:: day_of_week
235
236 - A (list of) integers from 0-6, where Sunday = 0 and Saturday =
237 6, that represent the days of a week that execution should
238 occur.
239 - A string representing a crontab pattern. This may get pretty
240 advanced, like `day_of_week="mon-fri"` (for weekdays only).
241 (Beware that `day_of_week="*/2"` does not literally mean
242 "every two days", but "every day that is divisible by two"!)
243
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
244 .. attribute:: day_of_month
245
246 - A (list of) integers from 1-31 that represents the days of the
247 month that execution should occur.
248 - A string representing a crontab pattern. This may get pretty
249 advanced, such as `day_of_month="2-30/3"` (for every even
250 numbered day) or `day_of_month="1-7,15-21"` (for the first and
251 third weeks of the month).
252
253 .. attribute:: month_of_year
254
255 - A (list of) integers from 1-12 that represents the months of
256 the year during which execution can occur.
257 - A string representing a crontab pattern. This may get pretty
258 advanced, such as `month_of_year="*/3"` (for the first month
259 of every quarter) or `month_of_year="2-12/2"` (for every even
260 numbered month).
261
262 It is important to realize that any day on which execution should
263 occur must be represented by entries in all three of the day and
264 month attributes. For example, if `day_of_week` is 0 and `day_of_month`
265 is every seventh day, only months that begin on Sunday and are also
266 in the `month_of_year` attribute will have execution events. Or,
267 `day_of_week` is 1 and `day_of_month` is "1-7,15-21" means every
268 first and third monday of every month present in `month_of_year`.
269
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
270 """
271
272 @staticmethod
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
273 def _expand_cronspec(cronspec, max_, min_=0):
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
274 """Takes the given cronspec argument in one of the forms::
275
276 int (like 7)
277 basestring (like '3-5,*/15', '*', or 'monday')
278 set (like set([0,15,30,45]))
279 list (like [8-17])
280
281 And convert it to an (expanded) set representing all time unit
282 values on which the crontab triggers. Only in case of the base
283 type being 'basestring', parsing occurs. (It is fast and
284 happens only once for each crontab instance, so there is no
285 significant performance overhead involved.)
286
287 For the other base types, merely Python type conversions happen.
288
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
289 The argument `max_` is needed to determine the expansion of '*'
290 and ranges.
291 The argument `min_` is needed to determine the expansion of '*'
292 and ranges for 1-based cronspecs, such as day of month or month
293 of year. The default is sufficient for minute, hour, and day of
294 week.
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
295
296 """
297 if isinstance(cronspec, int):
298 result = set([cronspec])
299 elif isinstance(cronspec, basestring):
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
300 result = crontab_parser(max_, min_).parse(cronspec)
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
301 elif isinstance(cronspec, set):
302 result = cronspec
303 elif is_iterable(cronspec):
304 result = set(cronspec)
305 else:
bffe590 Merge branch 'master' into dbschedule
Ask Solem authored
306 raise TypeError(
307 "Argument cronspec needs to be of any of the "
308 "following types: int, basestring, or an iterable type. "
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
309 "'%s' was given." % type(cronspec))
310
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
311 # assure the result does not preceed the min or exceed the max
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
312 for number in result:
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
313 if number >= max_ + min_ or number < min_:
bffe590 Merge branch 'master' into dbschedule
Ask Solem authored
314 raise ValueError(
315 "Invalid crontab pattern. Valid "
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
316 "range is %d-%d. '%d' was found." %
317 (min_, max_ - 1 + min_, number))
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
318
319 return result
320
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
321 def _delta_to_next(self, last_run_at, next_hour, next_minute):
322 """
323 Takes a datetime of last run, next minute and hour, and
324 returns a relativedelta for the next scheduled day and time.
325 Only called when day_of_month and/or month_of_year cronspec
326 is specified to further limit scheduled task execution.
327 """
328 from bisect import bisect, bisect_left
329
330 datedata = AttributeDict(year=last_run_at.year)
331 days_of_month = sorted(self.day_of_month)
332 months_of_year = sorted(self.month_of_year)
333
334 def day_out_of_range(year, month, day):
335 try:
336 datetime(year=year, month=month, day=day)
337 except ValueError:
338 return True
339 return False
340
341 def roll_over():
e6c19ad @ask Cosmetics
ask authored
342 while 1:
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
343 flag = (datedata.dom == len(days_of_month) or
344 day_out_of_range(datedata.year,
345 months_of_year[datedata.moy],
346 days_of_month[datedata.dom]))
347 if flag:
348 datedata.dom = 0
349 datedata.moy += 1
350 if datedata.moy == len(months_of_year):
351 datedata.moy = 0
352 datedata.year += 1
353 else:
354 break
355
356 if last_run_at.month in self.month_of_year:
357 datedata.dom = bisect(days_of_month, last_run_at.day)
358 datedata.moy = bisect_left(months_of_year, last_run_at.month)
359 else:
360 datedata.dom = 0
361 datedata.moy = bisect(months_of_year, last_run_at.month)
362 roll_over()
363
364 while not (datetime(year=datedata.year,
365 month=months_of_year[datedata.moy],
366 day=days_of_month[datedata.dom]
367 ).isoweekday() % 7
368 ) in self.day_of_week:
369 datedata.dom += 1
370 roll_over()
371
372 return relativedelta(year=datedata.year,
373 month=months_of_year[datedata.moy],
374 day=days_of_month[datedata.dom],
375 hour=next_hour,
376 minute=next_minute,
377 second=0,
378 microsecond=0)
379
380 def __init__(self, minute='*', hour='*', day_of_week='*',
381 day_of_month='*', month_of_year='*', nowfun=None):
ab7f041 Cosmetics
Ask Solem authored
382 self._orig_minute = minute
383 self._orig_hour = hour
384 self._orig_day_of_week = day_of_week
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
385 self._orig_day_of_month = day_of_month
386 self._orig_month_of_year = month_of_year
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
387 self.hour = self._expand_cronspec(hour, 24)
388 self.minute = self._expand_cronspec(minute, 60)
389 self.day_of_week = self._expand_cronspec(day_of_week, 7)
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
390 self.day_of_month = self._expand_cronspec(day_of_month, 31, 1)
391 self.month_of_year = self._expand_cronspec(month_of_year, 12, 1)
c86a7df @ask The current datetime now taken from loader.now
ask authored
392 self.nowfun = nowfun or current_app.now
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
393
ab7f041 Cosmetics
Ask Solem authored
394 def __repr__(self):
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
395 return ("<crontab: %s %s %s %s %s (m/h/d/dM/MY)>" %
396 (self._orig_minute or "*",
397 self._orig_hour or "*",
398 self._orig_day_of_week or "*",
399 self._orig_day_of_month or "*",
400 self._orig_month_of_year or "*"))
ab7f041 Cosmetics
Ask Solem authored
401
afad5d2 schedules.crontab: Implement __reduce__ so crontab can be pickled.
Ask Solem authored
402 def __reduce__(self):
ab7f041 Cosmetics
Ask Solem authored
403 return (self.__class__, (self._orig_minute,
404 self._orig_hour,
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
405 self._orig_day_of_week,
406 self._orig_day_of_month,
407 self._orig_month_of_year), None)
afad5d2 schedules.crontab: Implement __reduce__ so crontab can be pickled.
Ask Solem authored
408
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
409 def remaining_estimate(self, last_run_at):
27b12d0 @jbochi Proper remaining_estimate for crontabs. No need to wake up the scheduler...
jbochi authored
410 """Returns when the periodic task should run next as a timedelta."""
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
411 dow_num = last_run_at.isoweekday() % 7 # Sunday is day 0, not day 7
412
413 execute_this_date = (last_run_at.month in self.month_of_year and
414 last_run_at.day in self.day_of_month and
415 dow_num in self.day_of_week)
cfb2c96 @berg Fix crontab scheduler -- for Sunday, datetime.isoweekday() == 7, not 0, ...
berg authored
416
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
417 execute_this_hour = (execute_this_date and
72dafab celery.schedules: Cosmetics
Ask Solem authored
418 last_run_at.hour in self.hour and
1dfe6d0 @ask Remove 2.4 workarounds
ask authored
419 last_run_at.minute < max(self.minute))
27b12d0 @jbochi Proper remaining_estimate for crontabs. No need to wake up the scheduler...
jbochi authored
420
421 if execute_this_hour:
72dafab celery.schedules: Cosmetics
Ask Solem authored
422 next_minute = min(minute for minute in self.minute
423 if minute > last_run_at.minute)
424 delta = relativedelta(minute=next_minute,
425 second=0,
426 microsecond=0)
27b12d0 @jbochi Proper remaining_estimate for crontabs. No need to wake up the scheduler...
jbochi authored
427 else:
428 next_minute = min(self.minute)
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
429 execute_today = (execute_this_date and
430 last_run_at.hour < max(self.hour))
27b12d0 @jbochi Proper remaining_estimate for crontabs. No need to wake up the scheduler...
jbochi authored
431
432 if execute_today:
72dafab celery.schedules: Cosmetics
Ask Solem authored
433 next_hour = min(hour for hour in self.hour
434 if hour > last_run_at.hour)
435 delta = relativedelta(hour=next_hour,
436 minute=next_minute,
437 second=0,
438 microsecond=0)
27b12d0 @jbochi Proper remaining_estimate for crontabs. No need to wake up the scheduler...
jbochi authored
439 else:
440 next_hour = min(self.hour)
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
441 all_dom_moy = (self._orig_day_of_month == "*" and
442 self._orig_month_of_year == "*")
443 if all_dom_moy:
444 next_day = min([day for day in self.day_of_week
445 if day > dow_num] or
446 self.day_of_week)
447 add_week = next_day == dow_num
448
449 delta = relativedelta(weeks=add_week and 1 or 0,
450 weekday=(next_day - 1) % 7,
451 hour=next_hour,
452 minute=next_minute,
453 second=0,
454 microsecond=0)
455 else:
456 delta = self._delta_to_next(last_run_at,
457 next_hour, next_minute)
72dafab celery.schedules: Cosmetics
Ask Solem authored
458
27b12d0 @jbochi Proper remaining_estimate for crontabs. No need to wake up the scheduler...
jbochi authored
459 return remaining(last_run_at, delta, now=self.nowfun())
f508afb Periodic Tasks deprecated in favor of CELERYBEAT_SCHEDULE setting.
Ask Solem authored
460
461 def is_due(self, last_run_at):
0afa1ef Docs: Replaced all occurences of ``literal`` with `literal`
Ask Solem authored
462 """Returns tuple of two items `(is_due, next_time_to_run)`,
27b12d0 @jbochi Proper remaining_estimate for crontabs. No need to wake up the scheduler...
jbochi authored
463 where next time to run is in seconds.
464
8d85334 Improved docs
Ask Solem authored
465 See :meth:`celery.schedules.schedule.is_due` for more information.
27b12d0 @jbochi Proper remaining_estimate for crontabs. No need to wake up the scheduler...
jbochi authored
466
467 """
468 rem_delta = self.remaining_estimate(last_run_at)
469 rem = timedelta_seconds(rem_delta)
470 due = rem == 0
471 if due:
472 rem_delta = self.remaining_estimate(last_run_at=self.nowfun())
473 rem = timedelta_seconds(rem_delta)
474 return due, rem
475
289b1a5 New tests for the new celery.beat (92% coverage)
Ask Solem authored
476 def __eq__(self, other):
477 if isinstance(other, crontab):
dc6508f Adds day of month and month of year cronspec options to crontab schedule...
Keith Perkins authored
478 return (other.month_of_year == self.month_of_year and
479 other.day_of_month == self.day_of_month and
480 other.day_of_week == self.day_of_week and
289b1a5 New tests for the new celery.beat (92% coverage)
Ask Solem authored
481 other.hour == self.hour and
482 other.minute == self.minute)
483 return other is self
484
7ddf622 All tests passing again
Ask Solem authored
485
486 def maybe_schedule(s, relative=False):
487 if isinstance(s, int):
488 s = timedelta(seconds=s)
489 if isinstance(s, timedelta):
490 return schedule(s, relative)
491 return s
Something went wrong with that request. Please try again.