Skip to content

Commit

Permalink
feat: expire submissions after 14 days (#7461)
Browse files Browse the repository at this point in the history
* feat: expire submissions after 14 days

* test: update test_cancel_stale_submissions
  • Loading branch information
jennifer-richards committed May 24, 2024
1 parent a1a3097 commit 1a2996e
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 10 deletions.
3 changes: 3 additions & 0 deletions ietf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,9 @@ def skip_unreadable_post(record):
# Max time to allow for validation before a submission is subject to cancellation
IDSUBMIT_MAX_VALIDATION_TIME = datetime.timedelta(minutes=20)

# Age at which a submission expires if not posted
IDSUBMIT_EXPIRATION_AGE = datetime.timedelta(days=14)

IDSUBMIT_MANUAL_STAGING_DIR = '/tmp/'

IDSUBMIT_FILE_TYPES = (
Expand Down
19 changes: 17 additions & 2 deletions ietf/submit/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,34 @@ def process_and_accept_uploaded_submission_task(submission_id):
@shared_task
def cancel_stale_submissions():
now = timezone.now()
stale_submissions = Submission.objects.filter(
# first check for submissions gone stale awaiting validation
stale_unvalidated_submissions = Submission.objects.filter(
state_id='validating',
).annotate(
submitted_at=Min('submissionevent__time'),
).filter(
submitted_at__lt=now - settings.IDSUBMIT_MAX_VALIDATION_TIME,
)
for subm in stale_submissions:
for subm in stale_unvalidated_submissions:
age = now - subm.submitted_at
log.log(f'Canceling stale submission (id={subm.id}, age={age})')
cancel_submission(subm)
create_submission_event(None, subm, 'Submission canceled: validation checks took too long')

# now check for expired submissions
expired_submissions = Submission.objects.exclude(
state_id__in=["posted", "cancel"],
).annotate(
submitted_at=Min("submissionevent__time"),
).filter(
submitted_at__lt=now - settings.IDSUBMIT_EXPIRATION_AGE,
)
for subm in expired_submissions:
age = now - subm.submitted_at
log.log(f'Canceling expired submission (id={subm.id}, age={age})')
cancel_submission(subm)
create_submission_event(None, subm, 'Submission canceled: expired without being posted')


@shared_task(bind=True)
def poke(self):
Expand Down
47 changes: 39 additions & 8 deletions ietf/submit/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from ietf.group.utils import setup_default_community_list_for_group
from ietf.meeting.models import Meeting
from ietf.meeting.factories import MeetingFactory
from ietf.name.models import FormalLanguageName
from ietf.name.models import DraftSubmissionStateName, FormalLanguageName
from ietf.person.models import Person
from ietf.person.factories import UserFactory, PersonFactory, EmailFactory
from ietf.submit.factories import SubmissionFactory, SubmissionExtResourceFactory
Expand Down Expand Up @@ -3136,28 +3136,59 @@ def test_status_of_validating_submission(self):
self.assertContains(r, s.name)
self.assertContains(r, 'This submission is being processed and validated.', status_code=200)

@override_settings(IDSUBMIT_MAX_VALIDATION_TIME=datetime.timedelta(minutes=30))
@override_settings(
IDSUBMIT_MAX_VALIDATION_TIME=datetime.timedelta(minutes=30),
IDSUBMIT_EXPIRATION_AGE=datetime.timedelta(minutes=90),
)
def test_cancel_stale_submissions(self):
# these will be lists of (Submission, "state_id") pairs
submissions_to_skip = []
submissions_to_cancel = []

# submissions in the validating state
fresh_submission = SubmissionFactory(state_id='validating')
fresh_submission.submissionevent_set.create(
desc='fake created event',
time=timezone.now() - datetime.timedelta(minutes=15),
)
submissions_to_skip.append((fresh_submission, "validating"))

stale_submission = SubmissionFactory(state_id='validating')
stale_submission.submissionevent_set.create(
desc='fake created event',
time=timezone.now() - datetime.timedelta(minutes=30, seconds=1),
)
submissions_to_cancel.append((stale_submission, "validating"))

# submissions in other states
for state in DraftSubmissionStateName.objects.filter(used=True).exclude(slug="validating"):
to_skip = SubmissionFactory(state_id=state.pk)
to_skip.submissionevent_set.create(
desc="fake created event",
time=timezone.now() - datetime.timedelta(minutes=45), # would be canceled if it were "validating"
)
submissions_to_skip.append((to_skip, state.pk))
to_expire = SubmissionFactory(state_id=state.pk)
to_expire.submissionevent_set.create(
desc="fake created event",
time=timezone.now() - datetime.timedelta(minutes=90, seconds=1),
)
if state.pk in ["posted", "cancel"]:
submissions_to_skip.append((to_expire, state.pk)) # these ones should not be expired regardless of age
else:
submissions_to_cancel.append(((to_expire, state.pk)))

cancel_stale_submissions()

fresh_submission = Submission.objects.get(pk=fresh_submission.pk)
self.assertEqual(fresh_submission.state_id, 'validating')
self.assertEqual(fresh_submission.submissionevent_set.count(), 1)
for _subm, original_state_id in submissions_to_skip:
subm = Submission.objects.get(pk=_subm.pk)
self.assertEqual(subm.state_id, original_state_id)
self.assertEqual(subm.submissionevent_set.count(), 1)

stale_submission = Submission.objects.get(pk=stale_submission.pk)
self.assertEqual(stale_submission.state_id, 'cancel')
self.assertEqual(stale_submission.submissionevent_set.count(), 2)
for _subm, _ in submissions_to_cancel:
subm = Submission.objects.get(pk=_subm.pk)
self.assertEqual(subm.state_id, "cancel")
self.assertEqual(subm.submissionevent_set.count(), 2)


class ApiSubmitTests(BaseSubmitTestCase):
Expand Down

0 comments on commit 1a2996e

Please sign in to comment.