diff options
-rw-r--r-- | apscheduler/triggers/base.py | 19 | ||||
-rw-r--r-- | docs/versionhistory.rst | 7 | ||||
-rw-r--r-- | tests/test_triggers.py | 20 |
3 files changed, 11 insertions, 35 deletions
diff --git a/apscheduler/triggers/base.py b/apscheduler/triggers/base.py index ce2526a..55d010d 100644 --- a/apscheduler/triggers/base.py +++ b/apscheduler/triggers/base.py @@ -22,27 +22,16 @@ class BaseTrigger(six.with_metaclass(ABCMeta)): def _apply_jitter(self, next_fire_time, jitter, now): """ - Randomize ``next_fire_time`` by adding or subtracting a random value (the jitter). If the - resulting datetime is in the past, returns the initial ``next_fire_time`` without jitter. - - ``next_fire_time - jitter <= result <= next_fire_time + jitter`` + Randomize ``next_fire_time`` by adding a random value (the jitter). :param datetime.datetime|None next_fire_time: next fire time without jitter applied. If ``None``, returns ``None``. - :param int|None jitter: maximum number of seconds to add or subtract to - ``next_fire_time``. If ``None`` or ``0``, returns ``next_fire_time`` + :param int|None jitter: maximum number of seconds to add to ``next_fire_time`` + (if ``None`` or ``0``, returns ``next_fire_time``) :param datetime.datetime now: current datetime :return datetime.datetime|None: next fire time with a jitter. """ if next_fire_time is None or not jitter: return next_fire_time - next_fire_time_with_jitter = next_fire_time + timedelta( - seconds=random.uniform(-jitter, jitter)) - - if next_fire_time_with_jitter < now: - # Next fire time with jitter is in the past. - # Ignore jitter to avoid false misfire. - return next_fire_time - - return next_fire_time_with_jitter + return next_fire_time + timedelta(seconds=random.uniform(0, jitter)) diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst index 79a40f7..bf33e4b 100644 --- a/docs/versionhistory.rst +++ b/docs/versionhistory.rst @@ -4,6 +4,13 @@ Version history To find out how to migrate your application from a previous version of APScheduler, see the :doc:`migration section <migration>`. +UNRELEASED +---------- + +* Ensure that jitter is always non-negative to prevent triggers from firing more often than + intended + + 3.6.3 ----- diff --git a/tests/test_triggers.py b/tests/test_triggers.py index a637485..ea0d1c1 100644 --- a/tests/test_triggers.py +++ b/tests/test_triggers.py @@ -50,16 +50,6 @@ class TestJitter(object): trigger = _DummyTriggerWithJitter(dt, 60) assert trigger.get_next_fire_time(None, now) == expected_dt - def test_jitter_in_past_but_initial_date_in_future(self, monkeypatch): - monkeypatch.setattr(random, 'uniform', lambda a, b: -30.) - - now = datetime(2017, 5, 25, 13, 40, 44) - dt = datetime(2017, 5, 25, 13, 40, 47) - expected_dt = dt - - trigger = _DummyTriggerWithJitter(dt, 60) - assert trigger.get_next_fire_time(None, now) == expected_dt - def test_jitter_in_future_but_initial_date_in_past(self, monkeypatch): monkeypatch.setattr(random, 'uniform', lambda a, b: 30.) @@ -70,16 +60,6 @@ class TestJitter(object): trigger = _DummyTriggerWithJitter(dt, 60) assert trigger.get_next_fire_time(None, now) == expected_dt - def test_jitter_misfire(self, monkeypatch): - monkeypatch.setattr(random, 'uniform', lambda a, b: -30.) - - now = datetime(2017, 5, 25, 13, 40, 44) - dt = datetime(2017, 5, 25, 13, 40, 40) - expected_dt = dt - - trigger = _DummyTriggerWithJitter(dt, 60) - assert trigger.get_next_fire_time(None, now) == expected_dt - def test_jitter_is_now(self, monkeypatch): monkeypatch.setattr(random, 'uniform', lambda a, b: 4.) |