Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cancel or delete stale pending and failed exports #1086

Merged
merged 5 commits into from
Aug 11, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions onadata/apps/viewer/tasks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import sys
from datetime import datetime, timedelta

from celery import task
from celery.task.schedules import crontab
from django.conf import settings
from django.shortcuts import get_object_or_404
from requests import ConnectionError
Expand Down Expand Up @@ -349,3 +351,39 @@ def delete_export(export_id):
export.delete()
return True
return False


@task.periodic_task(
run_every=(crontab(hour='*/7')),
ignore_result=True
)
def check_pending_exports():
"""
Exports that have not completed within a set time should be marked as
failed
"""
h = settings.EXPORT_TASK_LIFESPAN
time_threshold = datetime.now() - timedelta(hours=h)
exports = Export.objects.filter(internal_status=Export.PENDING,
created_on__lt=time_threshold)
for export in exports:
export.internal_status = Export.FAILED
export.save()
return True


@task.periodic_task(
run_every=(crontab(hour='*/7')),
ignore_result=True
)
def delete_old_failed_exports():
"""
Delete old failed exports
"""
h = settings.EXPORT_TASK_LIFESPAN
time_threshold = datetime.now() - timedelta(hours=h)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably use the time zone aware django.utils.timezone.now().
The h could probably be more descriptive like task_lifespan.

exports = Export.objects.filter(internal_status=Export.FAILED,
created_on__lt=time_threshold)
for export in exports:
delete_export.delay(export.id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you chose to delete the export in a different task considering this is already task? Possible use queryset deletion, exports.delet().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had seen that there was a task created to specifically delete exports that was used elsewhere, and so I chose to use it - to keep things consistent.

return True
10 changes: 10 additions & 0 deletions onadata/apps/viewer/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from onadata.apps.main.tests.test_base import TestBase
from onadata.apps.viewer.models.export import Export
from onadata.apps.viewer.tasks import create_async_export
from onadata.apps.viewer.tasks import check_pending_exports
from onadata.apps.viewer.tasks import delete_old_failed_exports


class TestExportTasks(TestBase):
Expand Down Expand Up @@ -38,3 +40,11 @@ def test_create_async(self):
self.assertTrue(export.id)
self.assertIn("username", options)
self.assertEquals(options.get("id_string"), self.xform.id_string)

def test_check_pending_exports(self):
result = check_pending_exports.delay()
self.assertTrue(result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably check that the function deletes exports and not that a task is created.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. And implemented.


def test_delete_old_failed_exports(self):
result = delete_old_failed_exports.delay()
self.assertTrue(result)
1 change: 1 addition & 0 deletions onadata/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ def configure_logging(logger, **kwargs):

# number of records on export or CSV import before a progress update
EXPORT_TASK_PROGRESS_UPDATE_BATCH = 1000
EXPORT_TASK_LIFESPAN = 6 # six hours

# default content length for submission requests
DEFAULT_CONTENT_LENGTH = 10000000
Expand Down