Skip to content
This repository has been archived by the owner on Aug 20, 2018. It is now read-only.

Commit

Permalink
Merge pull request #167 from bobsilverberg/expire_one_time_tasks
Browse files Browse the repository at this point in the history
Bug 1048353 - One time tasks need expiration date
  • Loading branch information
bobsilverberg committed Aug 14, 2014
2 parents 0c1ea3e + 46e7525 commit 2627b20
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 2 deletions.
3 changes: 3 additions & 0 deletions oneanddone/settings/base.py
Expand Up @@ -197,6 +197,9 @@ def _request_args():

# Project-specific Settings
##############################################################################
# Number of days that a one-time task attempt can be open before it expires
TASK_ATTEMPT_EXPIRATION_DURATION = 30

# Whitelisted tags allowed to be used in task instructions.
INSTRUCTIONS_ALLOWED_TAGS = [
'a',
Expand Down
Empty file.
Empty file.
14 changes: 14 additions & 0 deletions oneanddone/tasks/management/commands/taskattemptcleanup.py
@@ -0,0 +1,14 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from django.core.management.base import BaseCommand

from oneanddone.tasks.models import TaskAttempt


class Command(BaseCommand):
help = 'Cleans up status of task attempts based on task data'

def handle(self, *args, **options):
closed = TaskAttempt.close_expired_onetime_attempts()
self.stdout.write('%s expired one-time attempts were closed\n' % closed)
18 changes: 17 additions & 1 deletion oneanddone/tasks/models.py
@@ -1,6 +1,8 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from datetime import timedelta

from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
Expand Down Expand Up @@ -206,10 +208,12 @@ class TaskAttempt(CachedModel, CreatedModifiedModel):
STARTED = 0
FINISHED = 1
ABANDONED = 2
CLOSED = 3
state = models.IntegerField(default=STARTED, choices=(
(STARTED, 'Started'),
(FINISHED, 'Finished'),
(ABANDONED, 'Abandoned')
(ABANDONED, 'Abandoned'),
(CLOSED, 'Closed')
))

def __unicode__(self):
Expand All @@ -218,6 +222,18 @@ def __unicode__(self):
class Meta(CreatedModifiedModel.Meta):
ordering = ['-modified']

@classmethod
def close_expired_onetime_attempts(self):
"""
Close any attempts for one-time tasks that have been open for over 30 days
"""
compare_date = timezone.now() - timedelta(days=settings.TASK_ATTEMPT_EXPIRATION_DURATION)
expired_onetime_attempts = self.objects.filter(
state=self.STARTED,
created__lte=compare_date,
task__repeatable=False)
return expired_onetime_attempts.update(state=self.CLOSED)


class Feedback(CachedModel, CreatedModifiedModel):
attempt = models.ForeignKey(TaskAttempt)
Expand Down
28 changes: 27 additions & 1 deletion oneanddone/tasks/tests/test_models.py
@@ -1,7 +1,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from datetime import datetime
from datetime import datetime, timedelta

from django.utils import timezone

Expand Down Expand Up @@ -266,3 +266,29 @@ def test_isnt_completed_no_attempts_task(self):
the task should not be completed.
"""
eq_(self.task_not_repeatable_no_attempts.is_completed, False)

def test_close_expired_onetime_attempts(self):
"""
The close_expired_onetime_attempts routine should close all
expired one-time attempts and return the number that were closed.
"""
user = UserFactory.create()
recent_attempt, expired_attempt_1, expired_attempt_2 = TaskAttemptFactory.create_batch(
3,
user=user,
state=TaskAttempt.STARTED,
task=self.task_not_repeatable_no_attempts)
recent_attempt.created = aware_datetime(2014, 1, 29)
recent_attempt.save()
expired_attempt_1.created = aware_datetime(2014, 1, 1)
expired_attempt_1.save()
expired_attempt_2.created = aware_datetime(2014, 1, 1)
expired_attempt_2.save()
eq_(self.task_not_repeatable_no_attempts.taskattempt_set.filter(state=TaskAttempt.STARTED).count(), 3)
with patch('oneanddone.tasks.models.timezone.now') as now:
now.return_value = aware_datetime(2014, 1, 31)
eq_(TaskAttempt.close_expired_onetime_attempts(), 2)
eq_(TaskAttempt.objects.filter(task=self.task_not_repeatable_no_attempts,
state=TaskAttempt.STARTED).count(), 1)
eq_(TaskAttempt.objects.filter(task=self.task_not_repeatable_no_attempts,
state=TaskAttempt.CLOSED).count(), 2)

0 comments on commit 2627b20

Please sign in to comment.