Skip to content

Commit

Permalink
Merge pull request #73 from Miksus/dev/cron-style
Browse files Browse the repository at this point in the history
ENH: Add cron scheduler
  • Loading branch information
Miksus authored Aug 12, 2022
2 parents 8684375 + 09e5bcc commit 05861b7
Show file tree
Hide file tree
Showing 43 changed files with 2,092 additions and 408 deletions.
10 changes: 10 additions & 0 deletions docs/code/conds/api/cron.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from rocketry.conds import cron

@app.task(cron('* * * * *'))
def do_minutely():
...

@app.task(cron('*/2 12-18 * Oct Fri'))
def do_complex():
"Run at every 2nd minute past every hour from 12 through 18 on Friday in October."
...
16 changes: 16 additions & 0 deletions docs/code/conds/api/cron_kwargs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from rocketry.conds import cron

@app.task(cron(minute="*/5"))
def do_simple():
"Run at every 5th minute"
...

@app.task(cron(minute="*/2", hour="7-18", day_of_month="1,2,3", month="Feb-Aug/2"))
def do_complex():
"""Run at:
- Every second minute
- Between 07:00 (7 a.m.) - 18:00 (6 p.m.)
- On 1st, 2nd and 3rd day of month
- From February to August every second month
"""
...
28 changes: 28 additions & 0 deletions docs/handbooks/conditions/api/cron.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

.. _cron:

Cron Scheduling
===============

Rocketry also natively supports `cron-like scheduling <https://en.wikipedia.org/wiki/Cron>`_.

You can input a cron statement as a string:

Examples
--------

.. literalinclude:: /code/conds/api/cron.py
:language: py

Or you can use named arguments:

.. literalinclude:: /code/conds/api/cron_kwargs.py
:language: py

See more from the official definition of cron.

.. note::

Unlike most of the condition, the cron condition checks whether the task
has run on the period (as standard with cron schedulers) and not whether
the task has finished on the given period.
1 change: 1 addition & 0 deletions docs/handbooks/conditions/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Here are some examples:

logical
periodical
cron
pipeline
task_status
scheduler
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ applications. It is simple, clean and extensive.
**Core functionalities:**

- Powerful scheduling syntax
- A lot of built-in scheduling options
- A lot of built-in scheduling options (including :ref:`cron <cron>`)
- Task parallelization
- Task parametrization
- Task pipelining
Expand Down
9 changes: 9 additions & 0 deletions docs/versions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
Version history
===============

- ``2.3.0``

- Add: Cron style scheduling
- Add: New condition, ``TaskRunnable``
- Add: ``always`` time period
- Fix: Various bugs related to ``Any``, ``All`` and ``StaticInterval`` time periods
- Fix: Integers as start and end in time periods
- Upd: Now time periods are immutable

- ``2.2.0``

- Add: Async support
Expand Down
14 changes: 12 additions & 2 deletions rocketry/conditions/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Callable, Union
from rocketry.conditions.scheduler import SchedulerStarted
from rocketry.conditions.task.task import DependFailure, DependFinish, DependSuccess, TaskFailed, TaskFinished, TaskStarted, TaskSucceeded
from rocketry.conditions.task.task import DependFailure, DependFinish, DependSuccess, TaskFailed, TaskFinished, TaskRunnable, TaskStarted, TaskSucceeded
from rocketry.core import (
BaseCondition
)
Expand All @@ -9,6 +9,7 @@
)
from rocketry.core.condition.base import All, Any, Not
from rocketry.core.task import Task
from rocketry.time import Cron
from .time import IsPeriod
from .task import TaskExecutable, TaskRunning
from rocketry.time import (
Expand Down Expand Up @@ -137,6 +138,15 @@ def every(past:str, based="run"):
else:
raise ValueError(f"Invalid status: {based}")

def cron(__expr=None, **kwargs):
if __expr:
args = __expr.split(" ")
else:
args = ()

period = Cron(*args, **kwargs)
return TaskRunnable(period=period)

# Task pipelining
# ---------------

Expand Down Expand Up @@ -188,4 +198,4 @@ def running(more_than:str=None, less_than=None, task=None):
# ---------

def scheduler_running(more_than:str=None, less_than=None):
return SchedulerStarted(period=TimeSpanDelta(near=more_than, far=less_than))
return SchedulerStarted(period=TimeSpanDelta(near=more_than, far=less_than))
31 changes: 31 additions & 0 deletions rocketry/conditions/task/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ def get_state(self, task=Task(), session=Session()):
isin_period = (
# TimeDelta has no __contains__. One cannot say whether now is "past 2 hours".
# And please tell why this does not raise an exception then? - Future me
# Because the period is used in the sub statements and TimeDelta is still accepted - Senior me
True
if isinstance(period, TimeDelta)
else IsPeriod(period=period).observe()
Expand Down Expand Up @@ -292,6 +293,36 @@ def _from_period(cls, span_type=None, **kwargs):
return cls(period=period)


class TaskRunnable(BaseCondition):
"""Condition for checking whether a given
task has not run (for given period).
Useful to set the given task to run once
in given period.
"""

def __init__(self, task=None, period=None):
self.period = period
self.task = task
super().__init__()

def get_state(self, task=Task(), session=Session()):
task = self.task if self.task is not None else task
period = self.period

has_not_run = TaskStarted(period=period, task=task) == 0

isin_period = (
True
if isinstance(period, TimeDelta)
else IsPeriod(period=period).observe()
)

return (
isin_period
and has_not_run.observe(task=task, session=session)
)


class DependFinish(DependMixin):
"""Condition for checking whether a given
task has not finished after running a dependent
Expand Down
3 changes: 2 additions & 1 deletion rocketry/conds/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
started, succeeded, failed, finished,

scheduler_running,
running
running,
cron
)
5 changes: 4 additions & 1 deletion rocketry/core/time/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
StaticInterval,
All, Any,

PARSERS
PARSERS,

# Constants
always,
)


Expand Down
Loading

0 comments on commit 05861b7

Please sign in to comment.