Skip to content

Commit

Permalink
Merge pull request #44 from Koed00/dev
Browse files Browse the repository at this point in the history
Adds a n-minutes option to the scheduler
  • Loading branch information
Koed00 committed Aug 6, 2015
2 parents 77395ac + dea61a8 commit a4aa0fa
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 9 deletions.
2 changes: 1 addition & 1 deletion django_q/__init__.py
Expand Up @@ -9,6 +9,6 @@
from .cluster import Cluster
from .monitor import Stat

VERSION = (0, 4, 6)
VERSION = (0, 5, 0)

default_app_config = 'django_q.apps.DjangoQConfig'
4 changes: 3 additions & 1 deletion django_q/cluster.py
Expand Up @@ -440,7 +440,9 @@ def scheduler(list_key=Conf.Q_LIST):
# set up the next run time
if not s.schedule_type == s.ONCE:
next_run = arrow.get(s.next_run)
if s.schedule_type == s.HOURLY:
if s.schedule_type == s.MINUTES:
next_run = next_run.replace(minutes=+(s.minutes or 1))
elif s.schedule_type == s.HOURLY:
next_run = next_run.replace(hours=+1)
elif s.schedule_type == s.DAILY:
next_run = next_run.replace(days=+1)
Expand Down
24 changes: 24 additions & 0 deletions django_q/migrations/0006_auto_20150805_1817.py
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('django_q', '0005_auto_20150718_1506'),
]

operations = [
migrations.AddField(
model_name='schedule',
name='minutes',
field=models.PositiveSmallIntegerField(help_text='Number of minutes for the Minutes type', blank=True, null=True),
),
migrations.AlterField(
model_name='schedule',
name='schedule_type',
field=models.CharField(max_length=1, choices=[('O', 'Once'), ('I', 'Minutes'), ('H', 'Hourly'), ('D', 'Daily'), ('W', 'Weekly'), ('M', 'Monthly'), ('Q', 'Quarterly'), ('Y', 'Yearly')], default='O', verbose_name='Schedule Type'),
),
]
4 changes: 4 additions & 0 deletions django_q/models.py
Expand Up @@ -137,6 +137,7 @@ class Schedule(models.Model):
args = models.TextField(null=True, blank=True, help_text=_("e.g. 1, 2, 'John'"))
kwargs = models.TextField(null=True, blank=True, help_text=_("e.g. x=1, y=2, name='John'"))
ONCE = 'O'
MINUTES = 'I'
HOURLY = 'H'
DAILY = 'D'
WEEKLY = 'W'
Expand All @@ -145,6 +146,7 @@ class Schedule(models.Model):
YEARLY = 'Y'
TYPE = (
(ONCE, _('Once')),
(MINUTES, _('Minutes')),
(HOURLY, _('Hourly')),
(DAILY, _('Daily')),
(WEEKLY, _('Weekly')),
Expand All @@ -153,6 +155,8 @@ class Schedule(models.Model):
(YEARLY, _('Yearly')),
)
schedule_type = models.CharField(max_length=1, choices=TYPE, default=TYPE[0][0], verbose_name=_('Schedule Type'))
minutes = models.PositiveSmallIntegerField(null=True, blank=True,
help_text=_('Number of minutes for the Minutes type'))
repeats = models.SmallIntegerField(default=-1, verbose_name=_('Repeats'), help_text=_('n = n times, -1 = forever'))
next_run = models.DateTimeField(verbose_name=_('Next Run'), default=timezone.now, null=True)
task = models.CharField(max_length=100, null=True, editable=False)
Expand Down
2 changes: 2 additions & 0 deletions django_q/tasks.py
Expand Up @@ -66,6 +66,7 @@ def schedule(func, *args, **kwargs):
name = kwargs.pop('name', None)
hook = kwargs.pop('hook', None)
schedule_type = kwargs.pop('schedule_type', Schedule.ONCE)
minutes = kwargs.pop('minutes', None)
repeats = kwargs.pop('repeats', -1)
next_run = kwargs.pop('next_run', timezone.now())

Expand All @@ -75,6 +76,7 @@ def schedule(func, *args, **kwargs):
args=args,
kwargs=kwargs,
schedule_type=schedule_type,
minutes=minutes,
repeats=repeats,
next_run=next_run
)
Expand Down
7 changes: 7 additions & 0 deletions django_q/tests/test_scheduler.py
Expand Up @@ -71,6 +71,13 @@ def test_scheduler(r):
hook='django_q.tests.tasks.result'
)
assert hasattr(always_schedule, 'pk') is True
# Minute schedule
minute_schedule = create_schedule('django_q.tests.tasks.word_multiply',
2,
word='django',
schedule_type=Schedule.MINUTES,
minutes=10)
assert hasattr(minute_schedule, 'pk') is True
# All other types
for t in Schedule.TYPE:
schedule = create_schedule('django_q.tests.tasks.word_multiply',
Expand Down
Binary file added docs/_static/scheduled.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/successful.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion docs/admin.rst
Expand Up @@ -11,9 +11,11 @@ Successful tasks
----------------

Shows all successfully executed tasks. Meaning they did not encounter any errors during execution.
From here you can look at details of each task or delete them. Use the group column to sort your results by schedule name or group id.
From here you can look at details of each task or delete them. Use the group filter to filter your results by schedule name or group id.
The table is searchable by `name`, `func` and `group`

.. image:: _static/successful.png

Uses the :class:`Success` proxy model.

.. tip::
Expand All @@ -36,6 +38,8 @@ Scheduled tasks

Here you can check on the status of your scheduled tasks, create, edit or delete them.

.. image:: _static/scheduled.png

Repeats
~~~~~~~
If you want a schedule to only run a finite amount of times, e.g. every hour for the next 24 hours, you can do that using the :attr:`Schedule.repeats` attribute.
Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Expand Up @@ -70,9 +70,9 @@
# built documents.
#
# The short X.Y version.
version = '0.4'
version = '0.5'
# The full version, including alpha/beta/rc tags.
release = '0.4.6'
release = '0.5.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
24 changes: 21 additions & 3 deletions docs/schedules.rst
Expand Up @@ -32,6 +32,14 @@ You can manage them through the :ref:`admin_page` or directly from your code wit
q_options={'timeout': 30},
schedule_type=Schedule.HOURLY)
# Run a schedule every 5 minutes, starting at 6.
import arrow
schedule('math.hypot',
3, 4,
schedule_type=Schedule.MINUTES,
minutes = 5,
next_run = arrow.utcnow().replace(hour=18, minute=0))
Management Commands
-------------------
Expand All @@ -55,15 +63,16 @@ If you want to schedule regular Django management commands, you can use the :mod
Reference
---------

.. py:function:: schedule(func, *args, name=None, hook=None, schedule_type='O', repeats=-1, next_run=now() , q_options=None, **kwargs)
.. py:function:: schedule(func, *args, name=None, hook=None, schedule_type='O', minutes=None, repeats=-1, next_run=now() , q_options=None, **kwargs)
Creates a schedule

:param str func: the function to schedule. Dotted strings only.
:param args: arguments for the scheduled function.
:param str name: An optional name for your schedule.
:param str hook: optional result hook function. Dotted strings only.
:param str schedule_type: (O)nce, (H)ourly, (D)aily, (W)eekly, (M)onthly, (Q)uarterly, (Y)early or :attr:`Schedule.TYPE`
:param str schedule_type: (O)nce, M(I)nutes, (H)ourly, (D)aily, (W)eekly, (M)onthly, (Q)uarterly, (Y)early or :attr:`Schedule.TYPE`
:param int minutes: Number of minutes for the Minutes type.
:param int repeats: Number of times to repeat schedule. -1=Always, 0=Never, n =n.
:param datetime next_run: Next or first scheduled execution datetime.
:param dict q_options: async options to use for this schedule
Expand Down Expand Up @@ -103,8 +112,13 @@ Reference

.. py:attribute:: TYPE
:attr:`ONCE`, :attr:`HOURLY`, :attr:`DAILY`, :attr:`WEEKLY`, :attr:`MONTHLY`, :attr:`QUARTERLY`, :attr:`YEARLY`
:attr:`ONCE`, :attr:`MINUTES`, :attr:`HOURLY`, :attr:`DAILY`, :attr:`WEEKLY`, :attr:`MONTHLY`, :attr:`QUARTERLY`, :attr:`YEARLY`


.. py:attribute:: minutes
The number of minutes the :attr:`MINUTES` schedule should use.
Is ignored for other schedule types.

.. py:attribute:: repeats
Expand Down Expand Up @@ -133,6 +147,10 @@ Reference
If it has a negative :attr:`repeats` it will be deleted after it has run.
If you want to keep the result, set :attr:`repeats` to a positive number.

.. py:attribute:: MINUTES
`'I'` will run every :attr:`minutes` after its first run.

.. py:attribute:: HOURLY
`'H'` the scheduled task will run every hour after its first run.
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -26,7 +26,7 @@ def run(self):

setup(
name='django-q',
version='0.4.6',
version='0.5.0',
author='Ilan Steemers',
author_email='koed00@gmail.com',
keywords='django task queue worker redis multiprocessing',
Expand Down

0 comments on commit a4aa0fa

Please sign in to comment.